From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- .../gnu/javax/activation/viewers/ImageViewer.java | 138 + .../gnu/javax/activation/viewers/TextEditor.java | 119 + .../gnu/javax/activation/viewers/TextViewer.java | 81 + .../classpath/gnu/javax/crypto/RSACipherImpl.java | 299 ++ .../gnu/javax/crypto/assembly/Assembly.java | 272 ++ .../gnu/javax/crypto/assembly/Cascade.java | 348 ++ .../gnu/javax/crypto/assembly/CascadeStage.java | 93 + .../javax/crypto/assembly/CascadeTransformer.java | 123 + .../javax/crypto/assembly/DeflateTransformer.java | 177 + .../gnu/javax/crypto/assembly/Direction.java | 78 + .../javax/crypto/assembly/LoopbackTransformer.java | 100 + .../gnu/javax/crypto/assembly/ModeStage.java | 112 + .../gnu/javax/crypto/assembly/Operation.java | 73 + .../javax/crypto/assembly/PaddingTransformer.java | 164 + .../classpath/gnu/javax/crypto/assembly/Stage.java | 202 ++ .../gnu/javax/crypto/assembly/Transformer.java | 421 +++ .../crypto/assembly/TransformerException.java | 140 + .../classpath/gnu/javax/crypto/cipher/Anubis.java | 491 +++ .../gnu/javax/crypto/cipher/BaseCipher.java | 249 ++ .../gnu/javax/crypto/cipher/Blowfish.java | 611 ++++ .../classpath/gnu/javax/crypto/cipher/Cast5.java | 987 +++++ .../gnu/javax/crypto/cipher/CipherFactory.java | 129 + libjava/classpath/gnu/javax/crypto/cipher/DES.java | 652 ++++ .../gnu/javax/crypto/cipher/IBlockCipher.java | 195 + .../gnu/javax/crypto/cipher/IBlockCipherSpi.java | 124 + .../classpath/gnu/javax/crypto/cipher/Khazad.java | 449 +++ .../gnu/javax/crypto/cipher/NullCipher.java | 108 + .../gnu/javax/crypto/cipher/Rijndael.java | 704 ++++ .../classpath/gnu/javax/crypto/cipher/Serpent.java | 1781 +++++++++ .../classpath/gnu/javax/crypto/cipher/Square.java | 425 +++ .../gnu/javax/crypto/cipher/TripleDES.java | 257 ++ .../classpath/gnu/javax/crypto/cipher/Twofish.java | 737 ++++ .../gnu/javax/crypto/cipher/WeakKeyException.java | 59 + .../gnu/javax/crypto/jce/DiffieHellmanImpl.java | 171 + .../classpath/gnu/javax/crypto/jce/GnuCrypto.java | 598 +++ .../classpath/gnu/javax/crypto/jce/GnuSasl.java | 124 + .../javax/crypto/jce/PBKDF2SecretKeyFactory.java | 218 ++ .../javax/crypto/jce/cipher/AES128KeyWrapSpi.java | 54 + .../javax/crypto/jce/cipher/AES192KeyWrapSpi.java | 54 + .../javax/crypto/jce/cipher/AES256KeyWrapSpi.java | 54 + .../gnu/javax/crypto/jce/cipher/AESKeyWrapSpi.java | 88 + .../gnu/javax/crypto/jce/cipher/AESSpi.java | 92 + .../gnu/javax/crypto/jce/cipher/ARCFourSpi.java | 183 + .../gnu/javax/crypto/jce/cipher/AnubisSpi.java | 54 + .../gnu/javax/crypto/jce/cipher/BlowfishSpi.java | 54 + .../gnu/javax/crypto/jce/cipher/Cast5Spi.java | 54 + .../gnu/javax/crypto/jce/cipher/CipherAdapter.java | 531 +++ .../gnu/javax/crypto/jce/cipher/DESSpi.java | 54 + .../jce/cipher/KeyWrappingAlgorithmAdapter.java | 423 +++ .../gnu/javax/crypto/jce/cipher/KhazadSpi.java | 54 + .../gnu/javax/crypto/jce/cipher/NullCipherSpi.java | 54 + .../gnu/javax/crypto/jce/cipher/PBES2.java | 1379 +++++++ .../gnu/javax/crypto/jce/cipher/RijndaelSpi.java | 54 + .../gnu/javax/crypto/jce/cipher/SerpentSpi.java | 54 + .../gnu/javax/crypto/jce/cipher/SquareSpi.java | 54 + .../crypto/jce/cipher/TripleDESKeyWrapSpi.java | 54 + .../gnu/javax/crypto/jce/cipher/TripleDESSpi.java | 54 + .../gnu/javax/crypto/jce/cipher/TwofishSpi.java | 54 + .../crypto/jce/key/AnubisKeyGeneratorImpl.java | 50 + .../crypto/jce/key/AnubisSecretKeyFactoryImpl.java | 47 + .../crypto/jce/key/BlowfishKeyGeneratorImpl.java | 50 + .../jce/key/BlowfishSecretKeyFactoryImpl.java | 47 + .../crypto/jce/key/Cast5KeyGeneratorImpl.java | 50 + .../crypto/jce/key/Cast5SecretKeyFactoryImpl.java | 47 + .../javax/crypto/jce/key/DESKeyGeneratorImpl.java | 68 + .../crypto/jce/key/DESSecretKeyFactoryImpl.java | 82 + .../crypto/jce/key/DESedeSecretKeyFactoryImpl.java | 82 + .../crypto/jce/key/KhazadKeyGeneratorImpl.java | 50 + .../crypto/jce/key/KhazadSecretKeyFactoryImpl.java | 47 + .../crypto/jce/key/RijndaelKeyGeneratorImpl.java | 50 + .../jce/key/RijndaelSecretKeyFactoryImpl.java | 47 + .../javax/crypto/jce/key/SecretKeyFactoryImpl.java | 87 + .../crypto/jce/key/SecretKeyGeneratorImpl.java | 111 + .../crypto/jce/key/SerpentKeyGeneratorImpl.java | 50 + .../jce/key/SerpentSecretKeyFactoryImpl.java | 47 + .../crypto/jce/key/SquareKeyGeneratorImpl.java | 50 + .../crypto/jce/key/SquareSecretKeyFactoryImpl.java | 47 + .../crypto/jce/key/TripleDESKeyGeneratorImpl.java | 50 + .../crypto/jce/key/TwofishKeyGeneratorImpl.java | 50 + .../jce/key/TwofishSecretKeyFactoryImpl.java | 47 + .../gnu/javax/crypto/jce/keyring/GnuKeyring.java | 507 +++ .../gnu/javax/crypto/jce/mac/HMacHavalSpi.java | 54 + .../gnu/javax/crypto/jce/mac/HMacMD2Spi.java | 54 + .../gnu/javax/crypto/jce/mac/HMacMD4Spi.java | 54 + .../gnu/javax/crypto/jce/mac/HMacMD5Spi.java | 54 + .../gnu/javax/crypto/jce/mac/HMacRipeMD128Spi.java | 54 + .../gnu/javax/crypto/jce/mac/HMacRipeMD160Spi.java | 54 + .../gnu/javax/crypto/jce/mac/HMacSHA160Spi.java | 54 + .../gnu/javax/crypto/jce/mac/HMacSHA256Spi.java | 54 + .../gnu/javax/crypto/jce/mac/HMacSHA384Spi.java | 54 + .../gnu/javax/crypto/jce/mac/HMacSHA512Spi.java | 54 + .../gnu/javax/crypto/jce/mac/HMacTigerSpi.java | 54 + .../gnu/javax/crypto/jce/mac/HMacWhirlpoolSpi.java | 54 + .../gnu/javax/crypto/jce/mac/MacAdapter.java | 136 + .../gnu/javax/crypto/jce/mac/OMacAnubisImpl.java | 50 + .../gnu/javax/crypto/jce/mac/OMacBlowfishImpl.java | 50 + .../gnu/javax/crypto/jce/mac/OMacCast5Impl.java | 50 + .../gnu/javax/crypto/jce/mac/OMacDESImpl.java | 50 + .../gnu/javax/crypto/jce/mac/OMacImpl.java | 140 + .../gnu/javax/crypto/jce/mac/OMacKhazadImpl.java | 50 + .../gnu/javax/crypto/jce/mac/OMacRijndaelImpl.java | 50 + .../gnu/javax/crypto/jce/mac/OMacSerpentImpl.java | 50 + .../gnu/javax/crypto/jce/mac/OMacSquareImpl.java | 50 + .../javax/crypto/jce/mac/OMacTripleDESImpl.java | 50 + .../gnu/javax/crypto/jce/mac/OMacTwofishImpl.java | 50 + .../gnu/javax/crypto/jce/mac/TMMH16Spi.java | 81 + .../gnu/javax/crypto/jce/mac/UHash32Spi.java | 54 + .../gnu/javax/crypto/jce/mac/UMac32Spi.java | 79 + .../crypto/jce/params/BlockCipherParameters.java | 149 + .../crypto/jce/params/DEREncodingException.java | 54 + .../gnu/javax/crypto/jce/params/DERReader.java | 139 + .../gnu/javax/crypto/jce/params/DERWriter.java | 143 + .../javax/crypto/jce/prng/ARCFourRandomSpi.java | 102 + .../gnu/javax/crypto/jce/prng/CSPRNGSpi.java | 97 + .../gnu/javax/crypto/jce/prng/FortunaImpl.java | 100 + .../gnu/javax/crypto/jce/prng/ICMRandomSpi.java | 206 ++ .../gnu/javax/crypto/jce/prng/UMacRandomSpi.java | 166 + .../gnu/javax/crypto/jce/sig/DHKeyFactory.java | 219 ++ .../crypto/jce/sig/DHKeyPairGeneratorSpi.java | 93 + .../gnu/javax/crypto/jce/sig/DHParameters.java | 222 ++ .../crypto/jce/sig/DHParametersGenerator.java | 152 + .../crypto/jce/spec/BlockCipherParameterSpec.java | 122 + .../javax/crypto/jce/spec/TMMHParameterSpec.java | 117 + .../javax/crypto/jce/spec/UMac32ParameterSpec.java | 73 + .../javax/crypto/key/BaseKeyAgreementParty.java | 168 + .../classpath/gnu/javax/crypto/key/GnuPBEKey.java | 95 + .../gnu/javax/crypto/key/GnuSecretKey.java | 131 + .../gnu/javax/crypto/key/IKeyAgreementParty.java | 100 + .../gnu/javax/crypto/key/IncomingMessage.java | 318 ++ .../javax/crypto/key/KeyAgreementException.java | 168 + .../gnu/javax/crypto/key/KeyAgreementFactory.java | 143 + .../gnu/javax/crypto/key/OutgoingMessage.java | 234 ++ .../javax/crypto/key/dh/DHKeyPairPKCS8Codec.java | 240 ++ .../gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java | 336 ++ .../javax/crypto/key/dh/DHKeyPairX509Codec.java | 255 ++ .../crypto/key/dh/DiffieHellmanKeyAgreement.java | 119 + .../javax/crypto/key/dh/DiffieHellmanReceiver.java | 117 + .../javax/crypto/key/dh/DiffieHellmanSender.java | 126 + .../javax/crypto/key/dh/ElGamalKeyAgreement.java | 115 + .../gnu/javax/crypto/key/dh/ElGamalReceiver.java | 99 + .../gnu/javax/crypto/key/dh/ElGamalSender.java | 112 + .../gnu/javax/crypto/key/dh/GnuDHKey.java | 174 + .../javax/crypto/key/dh/GnuDHKeyPairGenerator.java | 235 ++ .../gnu/javax/crypto/key/dh/GnuDHPrivateKey.java | 200 + .../gnu/javax/crypto/key/dh/GnuDHPublicKey.java | 196 + .../classpath/gnu/javax/crypto/key/dh/RFC2631.java | 217 ++ .../gnu/javax/crypto/key/srp6/SRP6Host.java | 161 + .../javax/crypto/key/srp6/SRP6KeyAgreement.java | 141 + .../gnu/javax/crypto/key/srp6/SRP6SaslClient.java | 90 + .../gnu/javax/crypto/key/srp6/SRP6SaslServer.java | 90 + .../gnu/javax/crypto/key/srp6/SRP6TLSClient.java | 155 + .../gnu/javax/crypto/key/srp6/SRP6TLSServer.java | 177 + .../gnu/javax/crypto/key/srp6/SRP6User.java | 163 + .../gnu/javax/crypto/key/srp6/SRPAlgorithm.java | 131 + .../gnu/javax/crypto/key/srp6/SRPKey.java | 147 + .../javax/crypto/key/srp6/SRPKeyPairGenerator.java | 282 ++ .../javax/crypto/key/srp6/SRPKeyPairRawCodec.java | 334 ++ .../gnu/javax/crypto/key/srp6/SRPPrivateKey.java | 227 ++ .../gnu/javax/crypto/key/srp6/SRPPublicKey.java | 175 + .../javax/crypto/keyring/AuthenticatedEntry.java | 176 + .../gnu/javax/crypto/keyring/BaseKeyring.java | 158 + .../gnu/javax/crypto/keyring/BinaryDataEntry.java | 111 + .../gnu/javax/crypto/keyring/CertPathEntry.java | 112 + .../gnu/javax/crypto/keyring/CertificateEntry.java | 128 + .../gnu/javax/crypto/keyring/CompressedEntry.java | 93 + .../gnu/javax/crypto/keyring/EncryptedEntry.java | 191 + .../classpath/gnu/javax/crypto/keyring/Entry.java | 179 + .../gnu/javax/crypto/keyring/EnvelopeEntry.java | 439 +++ .../javax/crypto/keyring/GnuPrivateKeyring.java | 368 ++ .../gnu/javax/crypto/keyring/GnuPublicKeyring.java | 151 + .../gnu/javax/crypto/keyring/IKeyring.java | 162 + .../gnu/javax/crypto/keyring/IPrivateKeyring.java | 144 + .../gnu/javax/crypto/keyring/IPublicKeyring.java | 82 + .../crypto/keyring/MalformedKeyringException.java | 55 + .../crypto/keyring/MaskableEnvelopeEntry.java | 135 + .../javax/crypto/keyring/MeteredInputStream.java | 127 + .../crypto/keyring/PasswordAuthenticatedEntry.java | 286 ++ .../crypto/keyring/PasswordEncryptedEntry.java | 293 ++ .../crypto/keyring/PasswordProtectedEntry.java | 57 + .../gnu/javax/crypto/keyring/PrimitiveEntry.java | 112 + .../gnu/javax/crypto/keyring/PrivateKeyEntry.java | 194 + .../gnu/javax/crypto/keyring/Properties.java | 203 ++ .../gnu/javax/crypto/keyring/PublicKeyEntry.java | 162 + .../classpath/gnu/javax/crypto/kwa/AESKeyWrap.java | 168 + .../javax/crypto/kwa/BaseKeyWrappingAlgorithm.java | 145 + .../javax/crypto/kwa/IKeyWrappingAlgorithm.java | 160 + .../javax/crypto/kwa/KeyUnwrappingException.java | 67 + .../crypto/kwa/KeyWrappingAlgorithmFactory.java | 110 + .../gnu/javax/crypto/kwa/TripleDESKeyWrap.java | 292 ++ .../classpath/gnu/javax/crypto/mac/BaseMac.java | 127 + libjava/classpath/gnu/javax/crypto/mac/HMac.java | 263 ++ .../gnu/javax/crypto/mac/HMacFactory.java | 111 + libjava/classpath/gnu/javax/crypto/mac/IMac.java | 181 + .../classpath/gnu/javax/crypto/mac/MacFactory.java | 130 + .../gnu/javax/crypto/mac/MacInputStream.java | 124 + .../gnu/javax/crypto/mac/MacOutputStream.java | 123 + libjava/classpath/gnu/javax/crypto/mac/OMAC.java | 303 ++ libjava/classpath/gnu/javax/crypto/mac/TMMH16.java | 339 ++ .../classpath/gnu/javax/crypto/mac/UHash32.java | 758 ++++ libjava/classpath/gnu/javax/crypto/mac/UMac32.java | 418 +++ .../classpath/gnu/javax/crypto/mode/BaseMode.java | 295 ++ libjava/classpath/gnu/javax/crypto/mode/CBC.java | 123 + libjava/classpath/gnu/javax/crypto/mode/CFB.java | 155 + libjava/classpath/gnu/javax/crypto/mode/CTR.java | 168 + libjava/classpath/gnu/javax/crypto/mode/EAX.java | 289 ++ libjava/classpath/gnu/javax/crypto/mode/ECB.java | 121 + .../gnu/javax/crypto/mode/IAuthenticatedMode.java | 56 + libjava/classpath/gnu/javax/crypto/mode/ICM.java | 181 + libjava/classpath/gnu/javax/crypto/mode/IMode.java | 123 + .../gnu/javax/crypto/mode/ModeFactory.java | 151 + libjava/classpath/gnu/javax/crypto/mode/OFB.java | 174 + .../classpath/gnu/javax/crypto/pad/BasePad.java | 193 + libjava/classpath/gnu/javax/crypto/pad/IPad.java | 127 + .../classpath/gnu/javax/crypto/pad/ISO10126.java | 109 + .../classpath/gnu/javax/crypto/pad/PKCS1_V1_5.java | 156 + libjava/classpath/gnu/javax/crypto/pad/PKCS7.java | 111 + .../classpath/gnu/javax/crypto/pad/PadFactory.java | 120 + libjava/classpath/gnu/javax/crypto/pad/SSL3.java | 90 + libjava/classpath/gnu/javax/crypto/pad/TBC.java | 118 + libjava/classpath/gnu/javax/crypto/pad/TLS1.java | 91 + .../javax/crypto/pad/WrongPaddingException.java | 48 + .../classpath/gnu/javax/crypto/prng/ARCFour.java | 137 + .../classpath/gnu/javax/crypto/prng/CSPRNG.java | 985 +++++ .../classpath/gnu/javax/crypto/prng/Fortuna.java | 349 ++ .../gnu/javax/crypto/prng/ICMGenerator.java | 306 ++ libjava/classpath/gnu/javax/crypto/prng/IPBE.java | 81 + .../classpath/gnu/javax/crypto/prng/PBKDF2.java | 184 + .../gnu/javax/crypto/prng/PRNGFactory.java | 115 + .../gnu/javax/crypto/prng/UMacGenerator.java | 186 + .../classpath/gnu/javax/crypto/sasl/AuthInfo.java | 129 + .../javax/crypto/sasl/AuthInfoProviderFactory.java | 67 + .../gnu/javax/crypto/sasl/ClientFactory.java | 168 + .../gnu/javax/crypto/sasl/ClientMechanism.java | 293 ++ .../crypto/sasl/ConfidentialityException.java | 82 + .../gnu/javax/crypto/sasl/IAuthInfoProvider.java | 116 + .../crypto/sasl/IAuthInfoProviderFactory.java | 55 + .../sasl/IllegalMechanismStateException.java | 84 + .../gnu/javax/crypto/sasl/InputBuffer.java | 272 ++ .../gnu/javax/crypto/sasl/IntegrityException.java | 83 + .../crypto/sasl/NoSuchMechanismException.java | 62 + .../gnu/javax/crypto/sasl/NoSuchUserException.java | 67 + .../gnu/javax/crypto/sasl/OutputBuffer.java | 198 + .../javax/crypto/sasl/SaslEncodingException.java | 66 + .../gnu/javax/crypto/sasl/SaslInputStream.java | 393 ++ .../gnu/javax/crypto/sasl/SaslOutputStream.java | 175 + .../classpath/gnu/javax/crypto/sasl/SaslUtil.java | 75 + .../gnu/javax/crypto/sasl/ServerFactory.java | 158 + .../gnu/javax/crypto/sasl/ServerMechanism.java | 294 ++ .../crypto/sasl/UserAlreadyExistsException.java | 70 + .../crypto/sasl/anonymous/AnonymousClient.java | 102 + .../crypto/sasl/anonymous/AnonymousServer.java | 90 + .../javax/crypto/sasl/anonymous/AnonymousUtil.java | 83 + .../sasl/crammd5/CramMD5AuthInfoProvider.java | 166 + .../javax/crypto/sasl/crammd5/CramMD5Client.java | 168 + .../javax/crypto/sasl/crammd5/CramMD5Registry.java | 60 + .../javax/crypto/sasl/crammd5/CramMD5Server.java | 158 + .../gnu/javax/crypto/sasl/crammd5/CramMD5Util.java | 122 + .../javax/crypto/sasl/crammd5/PasswordFile.java | 240 ++ .../gnu/javax/crypto/sasl/plain/PasswordFile.java | 245 ++ .../crypto/sasl/plain/PlainAuthInfoProvider.java | 166 + .../gnu/javax/crypto/sasl/plain/PlainClient.java | 156 + .../gnu/javax/crypto/sasl/plain/PlainRegistry.java | 57 + .../gnu/javax/crypto/sasl/plain/PlainServer.java | 155 + .../classpath/gnu/javax/crypto/sasl/srp/CALG.java | 221 ++ .../gnu/javax/crypto/sasl/srp/ClientStore.java | 155 + .../classpath/gnu/javax/crypto/sasl/srp/IALG.java | 128 + .../classpath/gnu/javax/crypto/sasl/srp/KDF.java | 140 + .../gnu/javax/crypto/sasl/srp/PasswordFile.java | 627 ++++ .../classpath/gnu/javax/crypto/sasl/srp/SRP.java | 255 ++ .../javax/crypto/sasl/srp/SRPAuthInfoProvider.java | 177 + .../gnu/javax/crypto/sasl/srp/SRPClient.java | 954 +++++ .../gnu/javax/crypto/sasl/srp/SRPRegistry.java | 165 + .../gnu/javax/crypto/sasl/srp/SRPServer.java | 842 +++++ .../gnu/javax/crypto/sasl/srp/SecurityContext.java | 140 + .../gnu/javax/crypto/sasl/srp/ServerStore.java | 177 + .../gnu/javax/crypto/sasl/srp/StoreEntry.java | 75 + .../gnu/javax/imageio/IIOInputStream.java | 102 + .../gnu/javax/imageio/bmp/BMPDecoder.java | 168 + .../gnu/javax/imageio/bmp/BMPEncoder.java | 119 + .../gnu/javax/imageio/bmp/BMPException.java | 47 + .../gnu/javax/imageio/bmp/BMPFileHeader.java | 151 + .../gnu/javax/imageio/bmp/BMPImageReader.java | 148 + .../gnu/javax/imageio/bmp/BMPImageReaderSpi.java | 116 + .../gnu/javax/imageio/bmp/BMPImageWriter.java | 195 + .../gnu/javax/imageio/bmp/BMPImageWriterSpi.java | 148 + .../gnu/javax/imageio/bmp/BMPInfoHeader.java | 317 ++ .../gnu/javax/imageio/bmp/DecodeBF16.java | 99 + .../gnu/javax/imageio/bmp/DecodeBF32.java | 103 + .../gnu/javax/imageio/bmp/DecodeRGB1.java | 94 + .../gnu/javax/imageio/bmp/DecodeRGB24.java | 77 + .../gnu/javax/imageio/bmp/DecodeRGB4.java | 90 + .../gnu/javax/imageio/bmp/DecodeRGB8.java | 88 + .../gnu/javax/imageio/bmp/DecodeRLE4.java | 175 + .../gnu/javax/imageio/bmp/DecodeRLE8.java | 142 + .../gnu/javax/imageio/bmp/EncodeRGB1.java | 128 + .../gnu/javax/imageio/bmp/EncodeRGB16.java | 129 + .../gnu/javax/imageio/bmp/EncodeRGB24.java | 129 + .../gnu/javax/imageio/bmp/EncodeRGB32.java | 129 + .../gnu/javax/imageio/bmp/EncodeRGB4.java | 128 + .../gnu/javax/imageio/bmp/EncodeRGB8.java | 127 + .../gnu/javax/imageio/bmp/EncodeRLE4.java | 269 ++ .../gnu/javax/imageio/bmp/EncodeRLE8.java | 234 ++ .../classpath/gnu/javax/imageio/gif/GIFFile.java | 709 ++++ .../gnu/javax/imageio/gif/GIFImageReader.java | 241 ++ .../gnu/javax/imageio/gif/GIFImageReaderSpi.java | 124 + libjava/classpath/gnu/javax/imageio/jpeg/DCT.java | 347 ++ .../gnu/javax/imageio/jpeg/HuffmanTable.java | 207 ++ .../gnu/javax/imageio/jpeg/JPEGComponent.java | 351 ++ .../gnu/javax/imageio/jpeg/JPEGDecoder.java | 625 ++++ .../gnu/javax/imageio/jpeg/JPEGException.java | 48 + .../gnu/javax/imageio/jpeg/JPEGFrame.java | 108 + .../javax/imageio/jpeg/JPEGImageInputStream.java | 188 + .../gnu/javax/imageio/jpeg/JPEGImageReader.java | 141 + .../gnu/javax/imageio/jpeg/JPEGImageReaderSpi.java | 137 + .../gnu/javax/imageio/jpeg/JPEGMarker.java | 205 ++ .../imageio/jpeg/JPEGMarkerFoundException.java | 50 + .../classpath/gnu/javax/imageio/jpeg/JPEGScan.java | 151 + .../gnu/javax/imageio/jpeg/YCbCr_ColorSpace.java | 113 + .../classpath/gnu/javax/imageio/jpeg/ZigZag.java | 520 +++ .../classpath/gnu/javax/imageio/png/PNGChunk.java | 283 ++ .../classpath/gnu/javax/imageio/png/PNGData.java | 104 + .../gnu/javax/imageio/png/PNGDecoder.java | 331 ++ .../gnu/javax/imageio/png/PNGEncoder.java | 233 ++ .../gnu/javax/imageio/png/PNGException.java | 48 + .../classpath/gnu/javax/imageio/png/PNGFile.java | 257 ++ .../classpath/gnu/javax/imageio/png/PNGFilter.java | 237 ++ .../classpath/gnu/javax/imageio/png/PNGGamma.java | 85 + .../classpath/gnu/javax/imageio/png/PNGHeader.java | 257 ++ .../gnu/javax/imageio/png/PNGICCProfile.java | 116 + .../gnu/javax/imageio/png/PNGImageReader.java | 224 ++ .../gnu/javax/imageio/png/PNGImageReaderSpi.java | 128 + .../gnu/javax/imageio/png/PNGPalette.java | 127 + .../classpath/gnu/javax/imageio/png/PNGPhys.java | 112 + .../classpath/gnu/javax/imageio/png/PNGTime.java | 83 + .../gnu/javax/management/ListenerData.java | 136 + libjava/classpath/gnu/javax/management/Server.java | 2233 ++++++++++++ .../classpath/gnu/javax/management/Translator.java | 550 +++ .../gnu/javax/naming/giop/ContextContinuation.java | 956 +++++ .../gnu/javax/naming/giop/CorbalocParser.java | 441 +++ .../javax/naming/giop/GiopNamingEnumeration.java | 187 + .../naming/giop/GiopNamingServiceFactory.java | 179 + .../naming/giop/GiopNamingServiceURLContext.java | 840 +++++ .../javax/naming/giop/ListBindingsEnumeration.java | 118 + .../gnu/javax/naming/giop/ListEnumeration.java | 118 + .../gnu/javax/naming/ictxImpl/trans/GnuName.java | 469 +++ .../url/corbaname/corbanameURLContextFactory.java | 53 + .../naming/jndi/url/rmi/ContextContinuation.java | 597 +++ .../jndi/url/rmi/ListBindingsEnumeration.java | 97 + .../javax/naming/jndi/url/rmi/ListEnumeration.java | 80 + .../javax/naming/jndi/url/rmi/RmiContinuation.java | 594 +++ .../naming/jndi/url/rmi/RmiNamingEnumeration.java | 130 + .../javax/naming/jndi/url/rmi/rmiURLContext.java | 637 ++++ .../naming/jndi/url/rmi/rmiURLContextFactory.java | 66 + .../gnu/javax/net/ssl/AbstractSessionContext.java | 288 ++ .../classpath/gnu/javax/net/ssl/EntropySource.java | 62 + .../gnu/javax/net/ssl/NullManagerParameters.java | 56 + .../gnu/javax/net/ssl/PreSharedKeyManager.java | 54 + .../net/ssl/PreSharedKeyManagerParameters.java | 83 + .../gnu/javax/net/ssl/PrivateCredentials.java | 363 ++ .../gnu/javax/net/ssl/SRPManagerParameters.java | 81 + .../gnu/javax/net/ssl/SRPTrustManager.java | 99 + .../gnu/javax/net/ssl/SSLCipherSuite.java | 142 + .../gnu/javax/net/ssl/SSLProtocolVersion.java | 54 + .../gnu/javax/net/ssl/SSLRecordHandler.java | 100 + libjava/classpath/gnu/javax/net/ssl/Session.java | 366 ++ .../gnu/javax/net/ssl/SessionStoreException.java | 59 + .../gnu/javax/net/ssl/StaticTrustAnchors.java | 1940 ++++++++++ .../javax/net/ssl/provider/AbstractHandshake.java | 1205 +++++++ .../gnu/javax/net/ssl/provider/Alert.java | 288 ++ .../gnu/javax/net/ssl/provider/AlertException.java | 101 + .../gnu/javax/net/ssl/provider/Builder.java | 66 + .../gnu/javax/net/ssl/provider/Certificate.java | 177 + .../javax/net/ssl/provider/CertificateBuilder.java | 94 + .../javax/net/ssl/provider/CertificateRequest.java | 155 + .../ssl/provider/CertificateRequestBuilder.java | 111 + .../net/ssl/provider/CertificateStatusRequest.java | 272 ++ .../net/ssl/provider/CertificateStatusType.java | 13 + .../javax/net/ssl/provider/CertificateType.java | 62 + .../gnu/javax/net/ssl/provider/CertificateURL.java | 388 ++ .../javax/net/ssl/provider/CertificateVerify.java | 83 + .../javax/net/ssl/provider/CipherAlgorithm.java | 47 + .../gnu/javax/net/ssl/provider/CipherSuite.java | 837 +++++ .../javax/net/ssl/provider/CipherSuiteList.java | 283 ++ .../ssl/provider/ClientCertificateTypeList.java | 227 ++ .../net/ssl/provider/ClientDHE_PSKParameters.java | 122 + .../ssl/provider/ClientDiffieHellmanPublic.java | 129 + .../javax/net/ssl/provider/ClientHandshake.java | 1153 ++++++ .../gnu/javax/net/ssl/provider/ClientHello.java | 240 ++ .../javax/net/ssl/provider/ClientHelloBuilder.java | 137 + .../gnu/javax/net/ssl/provider/ClientHelloV2.java | 158 + .../javax/net/ssl/provider/ClientKeyExchange.java | 132 + .../net/ssl/provider/ClientKeyExchangeBuilder.java | 75 + .../net/ssl/provider/ClientPSKParameters.java | 121 + .../net/ssl/provider/ClientRSA_PSKParameters.java | 122 + .../javax/net/ssl/provider/CompressionMethod.java | 69 + .../net/ssl/provider/CompressionMethodList.java | 281 ++ .../gnu/javax/net/ssl/provider/Constructed.java | 86 + .../gnu/javax/net/ssl/provider/ContentType.java | 89 + .../gnu/javax/net/ssl/provider/Debug.java | 66 + .../gnu/javax/net/ssl/provider/DelegatedTask.java | 93 + .../gnu/javax/net/ssl/provider/DiffieHellman.java | 289 ++ .../javax/net/ssl/provider/EmptyExchangeKeys.java | 77 + .../net/ssl/provider/EncryptedPreMasterSecret.java | 148 + .../gnu/javax/net/ssl/provider/ExchangeKeys.java | 54 + .../gnu/javax/net/ssl/provider/Extension.java | 246 ++ .../gnu/javax/net/ssl/provider/ExtensionList.java | 290 ++ .../gnu/javax/net/ssl/provider/Finished.java | 173 + .../gnu/javax/net/ssl/provider/Handshake.java | 299 ++ .../gnu/javax/net/ssl/provider/HelloRequest.java | 72 + .../net/ssl/provider/InputSecurityParameters.java | 334 ++ .../gnu/javax/net/ssl/provider/Jessie.java | 102 + .../net/ssl/provider/KeyExchangeAlgorithm.java | 57 + .../gnu/javax/net/ssl/provider/MacAlgorithm.java | 47 + .../gnu/javax/net/ssl/provider/MacException.java | 53 + .../javax/net/ssl/provider/MaxFragmentLength.java | 59 + .../net/ssl/provider/OutputSecurityParameters.java | 294 ++ .../provider/PreSharedKeyManagerFactoryImpl.java | 118 + .../javax/net/ssl/provider/ProtocolVersion.java | 200 + .../gnu/javax/net/ssl/provider/Random.java | 150 + .../gnu/javax/net/ssl/provider/Record.java | 198 + .../net/ssl/provider/SRPTrustManagerFactory.java | 223 ++ .../gnu/javax/net/ssl/provider/SSLContextImpl.java | 315 ++ .../gnu/javax/net/ssl/provider/SSLEngineImpl.java | 842 +++++ .../gnu/javax/net/ssl/provider/SSLHMac.java | 158 + .../net/ssl/provider/SSLRSASignatureImpl.java | 234 ++ .../gnu/javax/net/ssl/provider/SSLRandom.java | 165 + .../ssl/provider/SSLServerSocketFactoryImpl.java | 108 + .../net/ssl/provider/SSLServerSocketImpl.java | 199 + .../net/ssl/provider/SSLSocketFactoryImpl.java | 143 + .../gnu/javax/net/ssl/provider/SSLSocketImpl.java | 740 ++++ .../javax/net/ssl/provider/SSLv3HMacMD5Impl.java | 116 + .../javax/net/ssl/provider/SSLv3HMacSHAImpl.java | 116 + .../net/ssl/provider/ServerDHE_PSKParameters.java | 148 + .../gnu/javax/net/ssl/provider/ServerDHParams.java | 248 ++ .../javax/net/ssl/provider/ServerHandshake.java | 1377 +++++++ .../gnu/javax/net/ssl/provider/ServerHello.java | 231 ++ .../javax/net/ssl/provider/ServerHelloBuilder.java | 131 + .../javax/net/ssl/provider/ServerHelloDone.java | 66 + .../javax/net/ssl/provider/ServerKeyExchange.java | 173 + .../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 + .../javax/net/ssl/provider/ServerRSAParams.java | 163 + .../net/ssl/provider/ServerRSA_PSKParameters.java | 62 + .../gnu/javax/net/ssl/provider/SessionImpl.java | 192 + .../gnu/javax/net/ssl/provider/Signature.java | 157 + .../javax/net/ssl/provider/SignatureAlgorithm.java | 62 + .../net/ssl/provider/SimpleSessionContext.java | 144 + .../gnu/javax/net/ssl/provider/TLSHMac.java | 137 + .../gnu/javax/net/ssl/provider/TLSRandom.java | 252 ++ .../gnu/javax/net/ssl/provider/TruncatedHMAC.java | 76 + .../javax/net/ssl/provider/TrustedAuthorities.java | 297 ++ .../net/ssl/provider/UnresolvedExtensionValue.java | 81 + .../classpath/gnu/javax/net/ssl/provider/Util.java | 495 +++ .../javax/net/ssl/provider/X500PrincipalList.java | 272 ++ .../net/ssl/provider/X509KeyManagerFactory.java | 396 ++ .../net/ssl/provider/X509TrustManagerFactory.java | 295 ++ .../gnu/javax/print/CupsIppOperation.java | 99 + .../gnu/javax/print/CupsMediaMapping.java | 176 + .../gnu/javax/print/CupsPrintService.java | 104 + .../gnu/javax/print/CupsPrintServiceLookup.java | 260 ++ libjava/classpath/gnu/javax/print/CupsServer.java | 288 ++ .../gnu/javax/print/PrintAttributeException.java | 148 + .../gnu/javax/print/PrintFlavorException.java | 120 + .../gnu/javax/print/PrintUriException.java | 140 + .../classpath/gnu/javax/print/PrinterDialog.java | 1722 +++++++++ .../gnu/javax/print/ipp/DocPrintJobImpl.java | 471 +++ .../gnu/javax/print/ipp/IppDelimiterTag.java | 99 + .../gnu/javax/print/ipp/IppException.java | 88 + .../javax/print/ipp/IppMultiDocPrintService.java | 87 + .../gnu/javax/print/ipp/IppPrintService.java | 924 +++++ .../classpath/gnu/javax/print/ipp/IppRequest.java | 875 +++++ .../classpath/gnu/javax/print/ipp/IppResponse.java | 787 ++++ .../gnu/javax/print/ipp/IppStatusCode.java | 185 + .../gnu/javax/print/ipp/IppUtilities.java | 553 +++ .../classpath/gnu/javax/print/ipp/IppValueTag.java | 170 + .../gnu/javax/print/ipp/MultiDocPrintJobImpl.java | 80 + .../javax/print/ipp/attribute/CharsetSyntax.java | 115 + .../print/ipp/attribute/DefaultValueAttribute.java | 59 + .../print/ipp/attribute/DetailedStatusMessage.java | 93 + .../print/ipp/attribute/DocumentAccessError.java | 93 + .../print/ipp/attribute/NaturalLanguageSyntax.java | 117 + .../print/ipp/attribute/RequestedAttributes.java | 132 + .../javax/print/ipp/attribute/StatusMessage.java | 92 + .../print/ipp/attribute/UnknownAttribute.java | 190 + .../ipp/attribute/defaults/CopiesDefault.java | 118 + .../attribute/defaults/DocumentFormatDefault.java | 106 + .../ipp/attribute/defaults/FinishingsDefault.java | 263 ++ .../attribute/defaults/JobHoldUntilDefault.java | 149 + .../ipp/attribute/defaults/JobPriorityDefault.java | 118 + .../ipp/attribute/defaults/JobSheetsDefault.java | 122 + .../print/ipp/attribute/defaults/MediaDefault.java | 105 + .../defaults/MultipleDocumentHandlingDefault.java | 152 + .../ipp/attribute/defaults/NumberUpDefault.java | 114 + .../defaults/OrientationRequestedDefault.java | 154 + .../attribute/defaults/PrintQualityDefault.java | 141 + .../defaults/PrinterResolutionDefault.java | 119 + .../print/ipp/attribute/defaults/SidesDefault.java | 150 + .../print/ipp/attribute/job/AttributesCharset.java | 93 + .../attribute/job/AttributesNaturalLanguage.java | 95 + .../attribute/job/JobDetailedStatusMessages.java | 92 + .../ipp/attribute/job/JobDocumentAccessErrors.java | 93 + .../gnu/javax/print/ipp/attribute/job/JobId.java | 87 + .../javax/print/ipp/attribute/job/JobMoreInfo.java | 87 + .../print/ipp/attribute/job/JobPrinterUri.java | 87 + .../print/ipp/attribute/job/JobStateMessage.java | 92 + .../gnu/javax/print/ipp/attribute/job/JobUri.java | 87 + .../ipp/attribute/printer/CharsetConfigured.java | 86 + .../ipp/attribute/printer/DocumentFormat.java | 111 + .../printer/MultipleOperationTimeOut.java | 86 + .../printer/NaturalLanguageConfigured.java | 86 + .../ipp/attribute/printer/PrinterCurrentTime.java | 107 + .../attribute/printer/PrinterDriverInstaller.java | 88 + .../ipp/attribute/printer/PrinterStateMessage.java | 94 + .../print/ipp/attribute/printer/PrinterUpTime.java | 86 + .../ipp/attribute/supported/CharsetSupported.java | 88 + .../attribute/supported/CompressionSupported.java | 161 + .../supported/DocumentFormatSupported.java | 92 + .../attribute/supported/FinishingsSupported.java | 302 ++ .../GeneratedNaturalLanguageSupported.java | 89 + .../attribute/supported/IppVersionsSupported.java | 122 + .../attribute/supported/JobHoldUntilSupported.java | 134 + .../attribute/supported/JobSheetsSupported.java | 148 + .../ipp/attribute/supported/MediaSupported.java | 116 + .../MultipleDocumentHandlingSupported.java | 176 + .../supported/MultipleDocumentJobsSupported.java | 119 + .../attribute/supported/OperationsSupported.java | 231 ++ .../supported/OrientationRequestedSupported.java | 178 + .../attribute/supported/PageRangesSupported.java | 117 + .../attribute/supported/PrintQualitySupported.java | 169 + .../supported/PrinterResolutionSupported.java | 142 + .../attribute/supported/PrinterUriSupported.java | 89 + .../ipp/attribute/supported/SidesSupported.java | 137 + .../supported/UriAuthenticationSupported.java | 142 + .../attribute/supported/UriSecuritySupported.java | 127 + .../classpath/gnu/javax/rmi/CORBA/CorbaInput.java | 297 ++ .../classpath/gnu/javax/rmi/CORBA/CorbaOutput.java | 219 ++ .../javax/rmi/CORBA/DefaultWriteObjectTester.java | 85 + .../gnu/javax/rmi/CORBA/DelegateFactory.java | 107 + .../rmi/CORBA/GetDelegateInstanceException.java | 55 + .../CORBA/PortableRemoteObjectDelegateImpl.java | 362 ++ .../gnu/javax/rmi/CORBA/RmiUtilities.java | 949 +++++ .../gnu/javax/rmi/CORBA/StubDelegateImpl.java | 310 ++ .../gnu/javax/rmi/CORBA/TieTargetRecord.java | 93 + .../gnu/javax/rmi/CORBA/UtilDelegateImpl.java | 744 ++++ .../javax/rmi/CORBA/ValueHandlerDelegateImpl.java | 163 + .../gnu/javax/security/auth/Password.java | 283 ++ .../security/auth/callback/AWTCallbackHandler.java | 454 +++ .../auth/callback/AbstractCallbackHandler.java | 295 ++ .../auth/callback/CertificateCallback.java | 64 + .../auth/callback/ConsoleCallbackHandler.java | 299 ++ .../auth/callback/DefaultCallbackHandler.java | 109 + .../javax/security/auth/callback/GnuCallbacks.java | 64 + .../auth/callback/SwingCallbackHandler.java | 587 +++ .../security/auth/login/ConfigFileParser.java | 346 ++ .../security/auth/login/ConfigFileTokenizer.java | 246 ++ .../security/auth/login/GnuConfiguration.java | 466 +++ .../gnu/javax/sound/AudioSecurityManager.java | 112 + .../javax/sound/midi/alsa/AlsaInputPortDevice.java | 130 + .../sound/midi/alsa/AlsaMidiDeviceProvider.java | 216 ++ .../sound/midi/alsa/AlsaMidiSequencerDevice.java | 515 +++ .../sound/midi/alsa/AlsaOutputPortDevice.java | 131 + .../gnu/javax/sound/midi/alsa/AlsaPortDevice.java | 150 + .../sound/midi/dssi/DSSIMidiDeviceProvider.java | 171 + .../gnu/javax/sound/midi/dssi/DSSISynthesizer.java | 742 ++++ .../sound/midi/file/ExtendedMidiFileFormat.java | 77 + .../javax/sound/midi/file/MidiDataInputStream.java | 83 + .../sound/midi/file/MidiDataOutputStream.java | 114 + .../gnu/javax/sound/midi/file/MidiFileReader.java | 378 ++ .../gnu/javax/sound/midi/file/MidiFileWriter.java | 197 + .../gnu/javax/sound/sampled/AU/AUReader.java | 210 ++ .../gnu/javax/sound/sampled/WAV/WAVReader.java | 236 ++ .../sound/sampled/gstreamer/GStreamerMixer.java | 248 ++ .../sampled/gstreamer/GStreamerMixerProvider.java | 71 + .../sampled/gstreamer/io/GstAudioFileReader.java | 185 + .../gstreamer/io/GstAudioFileReaderNativePeer.java | 284 ++ .../sampled/gstreamer/io/GstAudioFileWriter.java | 80 + .../sound/sampled/gstreamer/io/GstInputStream.java | 119 + .../sound/sampled/gstreamer/lines/GstDataLine.java | 151 + .../sampled/gstreamer/lines/GstNativeDataLine.java | 77 + .../sound/sampled/gstreamer/lines/GstPipeline.java | 415 +++ .../sampled/gstreamer/lines/GstSourceDataLine.java | 153 + .../gnu/javax/swing/plaf/gnu/GNULookAndFeel.java | 266 ++ .../gnu/javax/swing/plaf/gtk/icons/Error.png | Bin 0 -> 1335 bytes .../gnu/javax/swing/plaf/gtk/icons/Inform.png | Bin 0 -> 250 bytes .../gnu/javax/swing/plaf/gtk/icons/JavaCup.png | Bin 0 -> 512 bytes .../javax/swing/plaf/gtk/icons/JavaCupLarge.png | Bin 0 -> 4341 bytes .../gnu/javax/swing/plaf/gtk/icons/Question.png | Bin 0 -> 250 bytes .../gnu/javax/swing/plaf/gtk/icons/README | 20 + .../gnu/javax/swing/plaf/gtk/icons/TreeClosed.png | Bin 0 -> 390 bytes .../javax/swing/plaf/gtk/icons/TreeLeaf-normal.png | Bin 0 -> 1522 bytes .../gnu/javax/swing/plaf/gtk/icons/TreeLeaf.png | Bin 0 -> 1007 bytes .../gnu/javax/swing/plaf/gtk/icons/TreeOpen.png | Bin 0 -> 315 bytes .../gnu/javax/swing/plaf/gtk/icons/Warn.png | Bin 0 -> 1335 bytes .../javax/swing/plaf/gtk/icons/file-folders.png | Bin 0 -> 843 bytes .../gnu/javax/swing/plaf/gtk/icons/slider.png | Bin 0 -> 179 bytes .../javax/swing/plaf/metal/CustomizableTheme.java | 218 ++ .../text/html/CharacterAttributeTranslator.java | 192 + .../javax/swing/text/html/CombinedAttributes.java | 213 ++ .../swing/text/html/ImageViewIconFactory.java | 282 ++ .../gnu/javax/swing/text/html/css/BorderStyle.java | 64 + .../gnu/javax/swing/text/html/css/BorderWidth.java | 78 + .../gnu/javax/swing/text/html/css/CSSColor.java | 170 + .../swing/text/html/css/CSSLexicalException.java | 60 + .../gnu/javax/swing/text/html/css/CSSParser.java | 503 +++ .../swing/text/html/css/CSSParserCallback.java | 81 + .../swing/text/html/css/CSSParserException.java | 62 + .../gnu/javax/swing/text/html/css/CSSScanner.java | 718 ++++ .../gnu/javax/swing/text/html/css/FontSize.java | 273 ++ .../gnu/javax/swing/text/html/css/FontStyle.java | 80 + .../gnu/javax/swing/text/html/css/FontWeight.java | 84 + .../gnu/javax/swing/text/html/css/Length.java | 283 ++ .../gnu/javax/swing/text/html/css/Selector.java | 245 ++ .../gnu/javax/swing/text/html/package.html | 50 + .../swing/text/html/parser/GnuParserDelegator.java | 179 + .../javax/swing/text/html/parser/HTML_401F.java | 3801 ++++++++++++++++++++ .../text/html/parser/SmallHtmlAttributeSet.java | 261 ++ .../gnu/javax/swing/text/html/parser/gnuDTD.java | 421 +++ .../swing/text/html/parser/htmlAttributeSet.java | 183 + .../swing/text/html/parser/htmlValidator.java | 622 ++++ .../text/html/parser/models/PCDATAonly_model.java | 62 + .../html/parser/models/TableRowContentModel.java | 77 + .../javax/swing/text/html/parser/models/list.java | 384 ++ .../swing/text/html/parser/models/noTagModel.java | 75 + .../javax/swing/text/html/parser/models/node.java | 339 ++ .../swing/text/html/parser/models/package.html | 53 + .../swing/text/html/parser/models/transformer.java | 201 ++ .../gnu/javax/swing/text/html/parser/package.html | 51 + .../swing/text/html/parser/support/Parser.java | 1532 ++++++++ .../html/parser/support/gnuStringIntMapper.java | 112 + .../swing/text/html/parser/support/low/Buffer.java | 238 ++ .../text/html/parser/support/low/Constants.java | 433 +++ .../text/html/parser/support/low/Location.java | 83 + .../html/parser/support/low/ParseException.java | 51 + .../swing/text/html/parser/support/low/Queue.java | 142 + .../html/parser/support/low/ReaderTokenizer.java | 373 ++ .../swing/text/html/parser/support/low/Token.java | 169 + .../swing/text/html/parser/support/low/node.java | 78 + .../text/html/parser/support/low/package.html | 47 + .../text/html/parser/support/low/pattern.java | 105 + .../swing/text/html/parser/support/package.html | 47 + .../html/parser/support/parameterDefaulter.java | 106 + .../text/html/parser/support/textPreProcessor.java | 189 + .../classpath/gnu/javax/swing/tree/GnuPath.java | 65 + 645 files changed, 133131 insertions(+) create mode 100644 libjava/classpath/gnu/javax/activation/viewers/ImageViewer.java create mode 100644 libjava/classpath/gnu/javax/activation/viewers/TextEditor.java create mode 100644 libjava/classpath/gnu/javax/activation/viewers/TextViewer.java create mode 100644 libjava/classpath/gnu/javax/crypto/RSACipherImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/assembly/Assembly.java create mode 100644 libjava/classpath/gnu/javax/crypto/assembly/Cascade.java create mode 100644 libjava/classpath/gnu/javax/crypto/assembly/CascadeStage.java create mode 100644 libjava/classpath/gnu/javax/crypto/assembly/CascadeTransformer.java create mode 100644 libjava/classpath/gnu/javax/crypto/assembly/DeflateTransformer.java create mode 100644 libjava/classpath/gnu/javax/crypto/assembly/Direction.java create mode 100644 libjava/classpath/gnu/javax/crypto/assembly/LoopbackTransformer.java create mode 100644 libjava/classpath/gnu/javax/crypto/assembly/ModeStage.java create mode 100644 libjava/classpath/gnu/javax/crypto/assembly/Operation.java create mode 100644 libjava/classpath/gnu/javax/crypto/assembly/PaddingTransformer.java create mode 100644 libjava/classpath/gnu/javax/crypto/assembly/Stage.java create mode 100644 libjava/classpath/gnu/javax/crypto/assembly/Transformer.java create mode 100644 libjava/classpath/gnu/javax/crypto/assembly/TransformerException.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/Anubis.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/BaseCipher.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/Blowfish.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/Cast5.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/CipherFactory.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/DES.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/IBlockCipher.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/IBlockCipherSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/Khazad.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/NullCipher.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/Rijndael.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/Serpent.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/Square.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/TripleDES.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/Twofish.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/WeakKeyException.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/DiffieHellmanImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/GnuCrypto.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/GnuSasl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/PBKDF2SecretKeyFactory.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/AES128KeyWrapSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/AES192KeyWrapSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/AES256KeyWrapSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/AESKeyWrapSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/AESSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/ARCFourSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/AnubisSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/BlowfishSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/Cast5Spi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/CipherAdapter.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/DESSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/KeyWrappingAlgorithmAdapter.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/KhazadSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/NullCipherSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/PBES2.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/RijndaelSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/SerpentSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/SquareSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/TripleDESKeyWrapSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/TripleDESSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/TwofishSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/AnubisKeyGeneratorImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/AnubisSecretKeyFactoryImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/BlowfishKeyGeneratorImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/BlowfishSecretKeyFactoryImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/Cast5KeyGeneratorImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/Cast5SecretKeyFactoryImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/DESKeyGeneratorImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/DESSecretKeyFactoryImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/DESedeSecretKeyFactoryImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/KhazadKeyGeneratorImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/KhazadSecretKeyFactoryImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/RijndaelKeyGeneratorImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/RijndaelSecretKeyFactoryImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/SecretKeyFactoryImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/SecretKeyGeneratorImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/SerpentKeyGeneratorImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/SerpentSecretKeyFactoryImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/SquareKeyGeneratorImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/SquareSecretKeyFactoryImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/TripleDESKeyGeneratorImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/TwofishKeyGeneratorImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/TwofishSecretKeyFactoryImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/keyring/GnuKeyring.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/HMacHavalSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD2Spi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD4Spi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD5Spi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/HMacRipeMD128Spi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/HMacRipeMD160Spi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA160Spi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA256Spi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA384Spi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA512Spi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/HMacTigerSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/HMacWhirlpoolSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/MacAdapter.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/OMacAnubisImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/OMacBlowfishImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/OMacCast5Impl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/OMacDESImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/OMacImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/OMacKhazadImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/OMacRijndaelImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/OMacSerpentImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/OMacSquareImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/OMacTripleDESImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/OMacTwofishImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/TMMH16Spi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/UHash32Spi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/UMac32Spi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/params/BlockCipherParameters.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/params/DEREncodingException.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/params/DERReader.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/params/DERWriter.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/prng/CSPRNGSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/prng/FortunaImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/prng/ICMRandomSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/prng/UMacRandomSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/sig/DHKeyFactory.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/sig/DHKeyPairGeneratorSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/sig/DHParameters.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/sig/DHParametersGenerator.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/spec/BlockCipherParameterSpec.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/spec/TMMHParameterSpec.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/spec/UMac32ParameterSpec.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/BaseKeyAgreementParty.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/GnuPBEKey.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/GnuSecretKey.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/IKeyAgreementParty.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/IncomingMessage.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/KeyAgreementException.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/KeyAgreementFactory.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/OutgoingMessage.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairPKCS8Codec.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairX509Codec.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanKeyAgreement.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanSender.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/dh/ElGamalReceiver.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/dh/ElGamalSender.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKey.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPrivateKey.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPublicKey.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/dh/RFC2631.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/srp6/SRP6Host.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslClient.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslServer.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSClient.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSServer.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/srp6/SRP6User.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/srp6/SRPAlgorithm.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/srp6/SRPKey.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/srp6/SRPPrivateKey.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/srp6/SRPPublicKey.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/AuthenticatedEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/BaseKeyring.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/BinaryDataEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/CertPathEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/CertificateEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/CompressedEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/EncryptedEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/Entry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/EnvelopeEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/GnuPrivateKeyring.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/GnuPublicKeyring.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/IKeyring.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/IPrivateKeyring.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/IPublicKeyring.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/MalformedKeyringException.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/MeteredInputStream.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/PasswordProtectedEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/PrimitiveEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/PrivateKeyEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/Properties.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/PublicKeyEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/kwa/AESKeyWrap.java create mode 100644 libjava/classpath/gnu/javax/crypto/kwa/BaseKeyWrappingAlgorithm.java create mode 100644 libjava/classpath/gnu/javax/crypto/kwa/IKeyWrappingAlgorithm.java create mode 100644 libjava/classpath/gnu/javax/crypto/kwa/KeyUnwrappingException.java create mode 100644 libjava/classpath/gnu/javax/crypto/kwa/KeyWrappingAlgorithmFactory.java create mode 100644 libjava/classpath/gnu/javax/crypto/kwa/TripleDESKeyWrap.java create mode 100644 libjava/classpath/gnu/javax/crypto/mac/BaseMac.java create mode 100644 libjava/classpath/gnu/javax/crypto/mac/HMac.java create mode 100644 libjava/classpath/gnu/javax/crypto/mac/HMacFactory.java create mode 100644 libjava/classpath/gnu/javax/crypto/mac/IMac.java create mode 100644 libjava/classpath/gnu/javax/crypto/mac/MacFactory.java create mode 100644 libjava/classpath/gnu/javax/crypto/mac/MacInputStream.java create mode 100644 libjava/classpath/gnu/javax/crypto/mac/MacOutputStream.java create mode 100644 libjava/classpath/gnu/javax/crypto/mac/OMAC.java create mode 100644 libjava/classpath/gnu/javax/crypto/mac/TMMH16.java create mode 100644 libjava/classpath/gnu/javax/crypto/mac/UHash32.java create mode 100644 libjava/classpath/gnu/javax/crypto/mac/UMac32.java create mode 100644 libjava/classpath/gnu/javax/crypto/mode/BaseMode.java create mode 100644 libjava/classpath/gnu/javax/crypto/mode/CBC.java create mode 100644 libjava/classpath/gnu/javax/crypto/mode/CFB.java create mode 100644 libjava/classpath/gnu/javax/crypto/mode/CTR.java create mode 100644 libjava/classpath/gnu/javax/crypto/mode/EAX.java create mode 100644 libjava/classpath/gnu/javax/crypto/mode/ECB.java create mode 100644 libjava/classpath/gnu/javax/crypto/mode/IAuthenticatedMode.java create mode 100644 libjava/classpath/gnu/javax/crypto/mode/ICM.java create mode 100644 libjava/classpath/gnu/javax/crypto/mode/IMode.java create mode 100644 libjava/classpath/gnu/javax/crypto/mode/ModeFactory.java create mode 100644 libjava/classpath/gnu/javax/crypto/mode/OFB.java create mode 100644 libjava/classpath/gnu/javax/crypto/pad/BasePad.java create mode 100644 libjava/classpath/gnu/javax/crypto/pad/IPad.java create mode 100644 libjava/classpath/gnu/javax/crypto/pad/ISO10126.java create mode 100644 libjava/classpath/gnu/javax/crypto/pad/PKCS1_V1_5.java create mode 100644 libjava/classpath/gnu/javax/crypto/pad/PKCS7.java create mode 100644 libjava/classpath/gnu/javax/crypto/pad/PadFactory.java create mode 100644 libjava/classpath/gnu/javax/crypto/pad/SSL3.java create mode 100644 libjava/classpath/gnu/javax/crypto/pad/TBC.java create mode 100644 libjava/classpath/gnu/javax/crypto/pad/TLS1.java create mode 100644 libjava/classpath/gnu/javax/crypto/pad/WrongPaddingException.java create mode 100644 libjava/classpath/gnu/javax/crypto/prng/ARCFour.java create mode 100644 libjava/classpath/gnu/javax/crypto/prng/CSPRNG.java create mode 100644 libjava/classpath/gnu/javax/crypto/prng/Fortuna.java create mode 100644 libjava/classpath/gnu/javax/crypto/prng/ICMGenerator.java create mode 100644 libjava/classpath/gnu/javax/crypto/prng/IPBE.java create mode 100644 libjava/classpath/gnu/javax/crypto/prng/PBKDF2.java create mode 100644 libjava/classpath/gnu/javax/crypto/prng/PRNGFactory.java create mode 100644 libjava/classpath/gnu/javax/crypto/prng/UMacGenerator.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/AuthInfo.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/AuthInfoProviderFactory.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/ClientFactory.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/ClientMechanism.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/ConfidentialityException.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/IAuthInfoProvider.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/IAuthInfoProviderFactory.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/IllegalMechanismStateException.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/InputBuffer.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/IntegrityException.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/NoSuchMechanismException.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/NoSuchUserException.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/OutputBuffer.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/SaslEncodingException.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/SaslInputStream.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/SaslOutputStream.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/SaslUtil.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/ServerFactory.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/ServerMechanism.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/UserAlreadyExistsException.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousClient.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousServer.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousUtil.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5AuthInfoProvider.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Client.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Registry.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Server.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Util.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/crammd5/PasswordFile.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/plain/PasswordFile.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/plain/PlainAuthInfoProvider.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/plain/PlainClient.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/plain/PlainRegistry.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/plain/PlainServer.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/srp/CALG.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/srp/ClientStore.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/srp/IALG.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/srp/KDF.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/srp/PasswordFile.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/srp/SRP.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/srp/SRPAuthInfoProvider.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/srp/SRPClient.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/srp/SRPRegistry.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/srp/SRPServer.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/srp/SecurityContext.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/srp/ServerStore.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/srp/StoreEntry.java create mode 100644 libjava/classpath/gnu/javax/imageio/IIOInputStream.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/BMPDecoder.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/BMPEncoder.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/BMPException.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/BMPFileHeader.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/BMPImageReader.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/BMPImageReaderSpi.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/BMPImageWriter.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/BMPImageWriterSpi.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/BMPInfoHeader.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/DecodeBF16.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/DecodeBF32.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/DecodeRGB1.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/DecodeRGB24.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/DecodeRGB4.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/DecodeRGB8.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/DecodeRLE4.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/DecodeRLE8.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB1.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB16.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB24.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB32.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB4.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB8.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/EncodeRLE4.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/EncodeRLE8.java create mode 100644 libjava/classpath/gnu/javax/imageio/gif/GIFFile.java create mode 100644 libjava/classpath/gnu/javax/imageio/gif/GIFImageReader.java create mode 100644 libjava/classpath/gnu/javax/imageio/gif/GIFImageReaderSpi.java create mode 100644 libjava/classpath/gnu/javax/imageio/jpeg/DCT.java create mode 100644 libjava/classpath/gnu/javax/imageio/jpeg/HuffmanTable.java create mode 100644 libjava/classpath/gnu/javax/imageio/jpeg/JPEGComponent.java create mode 100644 libjava/classpath/gnu/javax/imageio/jpeg/JPEGDecoder.java create mode 100644 libjava/classpath/gnu/javax/imageio/jpeg/JPEGException.java create mode 100644 libjava/classpath/gnu/javax/imageio/jpeg/JPEGFrame.java create mode 100644 libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageInputStream.java create mode 100644 libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageReader.java create mode 100644 libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageReaderSpi.java create mode 100644 libjava/classpath/gnu/javax/imageio/jpeg/JPEGMarker.java create mode 100644 libjava/classpath/gnu/javax/imageio/jpeg/JPEGMarkerFoundException.java create mode 100644 libjava/classpath/gnu/javax/imageio/jpeg/JPEGScan.java create mode 100644 libjava/classpath/gnu/javax/imageio/jpeg/YCbCr_ColorSpace.java create mode 100644 libjava/classpath/gnu/javax/imageio/jpeg/ZigZag.java create mode 100644 libjava/classpath/gnu/javax/imageio/png/PNGChunk.java create mode 100644 libjava/classpath/gnu/javax/imageio/png/PNGData.java create mode 100644 libjava/classpath/gnu/javax/imageio/png/PNGDecoder.java create mode 100644 libjava/classpath/gnu/javax/imageio/png/PNGEncoder.java create mode 100644 libjava/classpath/gnu/javax/imageio/png/PNGException.java create mode 100644 libjava/classpath/gnu/javax/imageio/png/PNGFile.java create mode 100644 libjava/classpath/gnu/javax/imageio/png/PNGFilter.java create mode 100644 libjava/classpath/gnu/javax/imageio/png/PNGGamma.java create mode 100644 libjava/classpath/gnu/javax/imageio/png/PNGHeader.java create mode 100644 libjava/classpath/gnu/javax/imageio/png/PNGICCProfile.java create mode 100644 libjava/classpath/gnu/javax/imageio/png/PNGImageReader.java create mode 100644 libjava/classpath/gnu/javax/imageio/png/PNGImageReaderSpi.java create mode 100644 libjava/classpath/gnu/javax/imageio/png/PNGPalette.java create mode 100644 libjava/classpath/gnu/javax/imageio/png/PNGPhys.java create mode 100644 libjava/classpath/gnu/javax/imageio/png/PNGTime.java create mode 100644 libjava/classpath/gnu/javax/management/ListenerData.java create mode 100644 libjava/classpath/gnu/javax/management/Server.java create mode 100644 libjava/classpath/gnu/javax/management/Translator.java create mode 100644 libjava/classpath/gnu/javax/naming/giop/ContextContinuation.java create mode 100644 libjava/classpath/gnu/javax/naming/giop/CorbalocParser.java create mode 100644 libjava/classpath/gnu/javax/naming/giop/GiopNamingEnumeration.java create mode 100644 libjava/classpath/gnu/javax/naming/giop/GiopNamingServiceFactory.java create mode 100644 libjava/classpath/gnu/javax/naming/giop/GiopNamingServiceURLContext.java create mode 100644 libjava/classpath/gnu/javax/naming/giop/ListBindingsEnumeration.java create mode 100644 libjava/classpath/gnu/javax/naming/giop/ListEnumeration.java create mode 100644 libjava/classpath/gnu/javax/naming/ictxImpl/trans/GnuName.java create mode 100644 libjava/classpath/gnu/javax/naming/jndi/url/corbaname/corbanameURLContextFactory.java create mode 100644 libjava/classpath/gnu/javax/naming/jndi/url/rmi/ContextContinuation.java create mode 100644 libjava/classpath/gnu/javax/naming/jndi/url/rmi/ListBindingsEnumeration.java create mode 100644 libjava/classpath/gnu/javax/naming/jndi/url/rmi/ListEnumeration.java create mode 100644 libjava/classpath/gnu/javax/naming/jndi/url/rmi/RmiContinuation.java create mode 100644 libjava/classpath/gnu/javax/naming/jndi/url/rmi/RmiNamingEnumeration.java create mode 100644 libjava/classpath/gnu/javax/naming/jndi/url/rmi/rmiURLContext.java create mode 100644 libjava/classpath/gnu/javax/naming/jndi/url/rmi/rmiURLContextFactory.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/AbstractSessionContext.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/EntropySource.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/NullManagerParameters.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/PreSharedKeyManager.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/PreSharedKeyManagerParameters.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/PrivateCredentials.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/SRPManagerParameters.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/SRPTrustManager.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/SSLCipherSuite.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/SSLProtocolVersion.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/SSLRecordHandler.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/Session.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/SessionStoreException.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/StaticTrustAnchors.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/AbstractHandshake.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/Alert.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/AlertException.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/Builder.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/Certificate.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/CertificateBuilder.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequest.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequestBuilder.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusRequest.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusType.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/CertificateType.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/CertificateURL.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/CertificateVerify.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/CipherAlgorithm.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/CipherSuite.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/CipherSuiteList.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ClientCertificateTypeList.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ClientDiffieHellmanPublic.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ClientHandshake.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ClientHello.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloBuilder.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloV2.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchange.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchangeBuilder.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ClientPSKParameters.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethod.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethodList.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/Constructed.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ContentType.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/Debug.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/DelegatedTask.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/DiffieHellman.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/EmptyExchangeKeys.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ExchangeKeys.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/Extension.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ExtensionList.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/Finished.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/Handshake.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/HelloRequest.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/InputSecurityParameters.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/Jessie.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/MacAlgorithm.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/MacException.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/MaxFragmentLength.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/OutputSecurityParameters.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ProtocolVersion.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/Random.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/Record.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/SSLContextImpl.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/SSLEngineImpl.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/SSLHMac.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/SSLRSASignatureImpl.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/SSLRandom.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketFactoryImpl.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketImpl.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketFactoryImpl.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketImpl.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacMD5Impl.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacSHAImpl.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ServerDHParams.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ServerHandshake.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ServerHello.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloBuilder.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloDone.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchange.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeBuilder.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeParams.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ServerNameList.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ServerPSKParameters.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ServerRSAParams.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/SessionImpl.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/Signature.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/SignatureAlgorithm.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/SimpleSessionContext.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/TLSHMac.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/TLSRandom.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/TruncatedHMAC.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/TrustedAuthorities.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/Util.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/X500PrincipalList.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java create mode 100644 libjava/classpath/gnu/javax/print/CupsIppOperation.java create mode 100644 libjava/classpath/gnu/javax/print/CupsMediaMapping.java create mode 100644 libjava/classpath/gnu/javax/print/CupsPrintService.java create mode 100644 libjava/classpath/gnu/javax/print/CupsPrintServiceLookup.java create mode 100644 libjava/classpath/gnu/javax/print/CupsServer.java create mode 100644 libjava/classpath/gnu/javax/print/PrintAttributeException.java create mode 100644 libjava/classpath/gnu/javax/print/PrintFlavorException.java create mode 100644 libjava/classpath/gnu/javax/print/PrintUriException.java create mode 100644 libjava/classpath/gnu/javax/print/PrinterDialog.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/DocPrintJobImpl.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/IppDelimiterTag.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/IppException.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/IppMultiDocPrintService.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/IppPrintService.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/IppRequest.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/IppResponse.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/IppStatusCode.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/IppUtilities.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/IppValueTag.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/MultiDocPrintJobImpl.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/CharsetSyntax.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/DefaultValueAttribute.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/DetailedStatusMessage.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/DocumentAccessError.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/NaturalLanguageSyntax.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/RequestedAttributes.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/StatusMessage.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/UnknownAttribute.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/defaults/CopiesDefault.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/defaults/DocumentFormatDefault.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/defaults/FinishingsDefault.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/defaults/JobHoldUntilDefault.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/defaults/JobPriorityDefault.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/defaults/JobSheetsDefault.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/defaults/MediaDefault.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/defaults/MultipleDocumentHandlingDefault.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/defaults/NumberUpDefault.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/defaults/OrientationRequestedDefault.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/defaults/PrintQualityDefault.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/defaults/PrinterResolutionDefault.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/defaults/SidesDefault.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/job/AttributesCharset.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/job/AttributesNaturalLanguage.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/job/JobDetailedStatusMessages.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/job/JobDocumentAccessErrors.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/job/JobId.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/job/JobMoreInfo.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/job/JobPrinterUri.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/job/JobStateMessage.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/job/JobUri.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/printer/CharsetConfigured.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/printer/DocumentFormat.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/printer/MultipleOperationTimeOut.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/printer/NaturalLanguageConfigured.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterCurrentTime.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterDriverInstaller.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterStateMessage.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterUpTime.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/CharsetSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/CompressionSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/DocumentFormatSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/FinishingsSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/GeneratedNaturalLanguageSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/IppVersionsSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/JobHoldUntilSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/JobSheetsSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/MediaSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/MultipleDocumentHandlingSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/MultipleDocumentJobsSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/OperationsSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/OrientationRequestedSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/PageRangesSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/PrintQualitySupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/PrinterResolutionSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/PrinterUriSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/SidesSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/UriAuthenticationSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/UriSecuritySupported.java create mode 100644 libjava/classpath/gnu/javax/rmi/CORBA/CorbaInput.java create mode 100644 libjava/classpath/gnu/javax/rmi/CORBA/CorbaOutput.java create mode 100644 libjava/classpath/gnu/javax/rmi/CORBA/DefaultWriteObjectTester.java create mode 100644 libjava/classpath/gnu/javax/rmi/CORBA/DelegateFactory.java create mode 100644 libjava/classpath/gnu/javax/rmi/CORBA/GetDelegateInstanceException.java create mode 100644 libjava/classpath/gnu/javax/rmi/CORBA/PortableRemoteObjectDelegateImpl.java create mode 100644 libjava/classpath/gnu/javax/rmi/CORBA/RmiUtilities.java create mode 100644 libjava/classpath/gnu/javax/rmi/CORBA/StubDelegateImpl.java create mode 100644 libjava/classpath/gnu/javax/rmi/CORBA/TieTargetRecord.java create mode 100644 libjava/classpath/gnu/javax/rmi/CORBA/UtilDelegateImpl.java create mode 100644 libjava/classpath/gnu/javax/rmi/CORBA/ValueHandlerDelegateImpl.java create mode 100644 libjava/classpath/gnu/javax/security/auth/Password.java create mode 100644 libjava/classpath/gnu/javax/security/auth/callback/AWTCallbackHandler.java create mode 100644 libjava/classpath/gnu/javax/security/auth/callback/AbstractCallbackHandler.java create mode 100644 libjava/classpath/gnu/javax/security/auth/callback/CertificateCallback.java create mode 100644 libjava/classpath/gnu/javax/security/auth/callback/ConsoleCallbackHandler.java create mode 100644 libjava/classpath/gnu/javax/security/auth/callback/DefaultCallbackHandler.java create mode 100644 libjava/classpath/gnu/javax/security/auth/callback/GnuCallbacks.java create mode 100644 libjava/classpath/gnu/javax/security/auth/callback/SwingCallbackHandler.java create mode 100644 libjava/classpath/gnu/javax/security/auth/login/ConfigFileParser.java create mode 100644 libjava/classpath/gnu/javax/security/auth/login/ConfigFileTokenizer.java create mode 100644 libjava/classpath/gnu/javax/security/auth/login/GnuConfiguration.java create mode 100644 libjava/classpath/gnu/javax/sound/AudioSecurityManager.java create mode 100644 libjava/classpath/gnu/javax/sound/midi/alsa/AlsaInputPortDevice.java create mode 100644 libjava/classpath/gnu/javax/sound/midi/alsa/AlsaMidiDeviceProvider.java create mode 100644 libjava/classpath/gnu/javax/sound/midi/alsa/AlsaMidiSequencerDevice.java create mode 100644 libjava/classpath/gnu/javax/sound/midi/alsa/AlsaOutputPortDevice.java create mode 100644 libjava/classpath/gnu/javax/sound/midi/alsa/AlsaPortDevice.java create mode 100644 libjava/classpath/gnu/javax/sound/midi/dssi/DSSIMidiDeviceProvider.java create mode 100644 libjava/classpath/gnu/javax/sound/midi/dssi/DSSISynthesizer.java create mode 100644 libjava/classpath/gnu/javax/sound/midi/file/ExtendedMidiFileFormat.java create mode 100644 libjava/classpath/gnu/javax/sound/midi/file/MidiDataInputStream.java create mode 100644 libjava/classpath/gnu/javax/sound/midi/file/MidiDataOutputStream.java create mode 100644 libjava/classpath/gnu/javax/sound/midi/file/MidiFileReader.java create mode 100644 libjava/classpath/gnu/javax/sound/midi/file/MidiFileWriter.java create mode 100644 libjava/classpath/gnu/javax/sound/sampled/AU/AUReader.java create mode 100644 libjava/classpath/gnu/javax/sound/sampled/WAV/WAVReader.java create mode 100644 libjava/classpath/gnu/javax/sound/sampled/gstreamer/GStreamerMixer.java create mode 100644 libjava/classpath/gnu/javax/sound/sampled/gstreamer/GStreamerMixerProvider.java create mode 100644 libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReader.java create mode 100644 libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReaderNativePeer.java create mode 100644 libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileWriter.java create mode 100644 libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstInputStream.java create mode 100644 libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstDataLine.java create mode 100644 libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstNativeDataLine.java create mode 100644 libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstPipeline.java create mode 100644 libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstSourceDataLine.java create mode 100644 libjava/classpath/gnu/javax/swing/plaf/gnu/GNULookAndFeel.java create mode 100644 libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Error.png create mode 100644 libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Inform.png create mode 100644 libjava/classpath/gnu/javax/swing/plaf/gtk/icons/JavaCup.png create mode 100644 libjava/classpath/gnu/javax/swing/plaf/gtk/icons/JavaCupLarge.png create mode 100644 libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Question.png create mode 100644 libjava/classpath/gnu/javax/swing/plaf/gtk/icons/README create mode 100644 libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeClosed.png create mode 100644 libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeLeaf-normal.png create mode 100644 libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeLeaf.png create mode 100644 libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeOpen.png create mode 100644 libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Warn.png create mode 100644 libjava/classpath/gnu/javax/swing/plaf/gtk/icons/file-folders.png create mode 100644 libjava/classpath/gnu/javax/swing/plaf/gtk/icons/slider.png create mode 100644 libjava/classpath/gnu/javax/swing/plaf/metal/CustomizableTheme.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/CharacterAttributeTranslator.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/CombinedAttributes.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/ImageViewIconFactory.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/css/BorderStyle.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/css/BorderWidth.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/css/CSSColor.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/css/CSSLexicalException.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/css/CSSParser.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/css/CSSParserCallback.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/css/CSSParserException.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/css/CSSScanner.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/css/FontSize.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/css/FontStyle.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/css/FontWeight.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/css/Length.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/css/Selector.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/package.html create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/GnuParserDelegator.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/HTML_401F.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/SmallHtmlAttributeSet.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/gnuDTD.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/htmlAttributeSet.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/htmlValidator.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/models/PCDATAonly_model.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/models/TableRowContentModel.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/models/list.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/models/noTagModel.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/models/node.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/models/package.html create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/models/transformer.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/package.html create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/support/Parser.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/support/gnuStringIntMapper.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Buffer.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Constants.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Location.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/support/low/ParseException.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Queue.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/support/low/ReaderTokenizer.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Token.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/support/low/node.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/support/low/package.html create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/support/low/pattern.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/support/package.html create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/support/parameterDefaulter.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/support/textPreProcessor.java create mode 100644 libjava/classpath/gnu/javax/swing/tree/GnuPath.java (limited to 'libjava/classpath/gnu/javax') diff --git a/libjava/classpath/gnu/javax/activation/viewers/ImageViewer.java b/libjava/classpath/gnu/javax/activation/viewers/ImageViewer.java new file mode 100644 index 000000000..5bddf7311 --- /dev/null +++ b/libjava/classpath/gnu/javax/activation/viewers/ImageViewer.java @@ -0,0 +1,138 @@ +/* ImageViewer.java -- Simple image display component. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.activation.viewers; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Image; +import java.awt.Graphics; +import java.awt.MediaTracker; +import java.awt.Toolkit; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.IOException; + +import javax.activation.CommandObject; +import javax.activation.DataHandler; + +/** + * Simple image display component. + * + * @author Chris Burdess + * @version 1.0.2 + */ +public class ImageViewer extends Component + implements CommandObject +{ + + private Image image; + + /** + * Returns the preferred size for this component (the image size). + */ + public Dimension getPreferredSize() + { + Dimension ps = new Dimension(0, 0); + if (image != null) + { + ps.width = image.getWidth(this); + ps.height = image.getHeight(this); + } + return ps; + } + + public void setCommandContext(String verb, DataHandler dh) + throws IOException + { + // Read image into a byte array + InputStream in = dh.getInputStream(); + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + byte[] buf = new byte[4096]; + for (int len = in.read(buf); len != -1; len = in.read(buf)) + bytes.write(buf, 0, len); + in.close(); + // Create and prepare the image + Toolkit toolkit = getToolkit(); + Image img = toolkit.createImage(bytes.toByteArray()); + try + { + MediaTracker tracker = new MediaTracker(this); + tracker.addImage(img, 0); + tracker.waitForID(0); + } + catch (InterruptedException e) + { + } + toolkit.prepareImage(img, -1, -1, this); + } + + /** + * Image bits arrive. + */ + public boolean imageUpdate(Image image, int flags, int x, int y, + int width, int height) + { + if ((flags & ALLBITS) != 0) + { + this.image = image; + invalidate(); + repaint(); + return false; + } + return ((flags & ERROR) == 0); + } + + /** + * Scale the image into this component's bounds. + */ + public void paint(Graphics g) + { + if (image != null) + { + Dimension is = new Dimension(image.getWidth(this), + image.getHeight(this)); + if (is.width > -1 && is.height > -1) + { + Dimension cs = getSize(); + g.drawImage(image, 0, 0, cs.width, cs.height, + 0, 0, is.width, is.height, this); + } + } + } + +} diff --git a/libjava/classpath/gnu/javax/activation/viewers/TextEditor.java b/libjava/classpath/gnu/javax/activation/viewers/TextEditor.java new file mode 100644 index 000000000..0eedc85db --- /dev/null +++ b/libjava/classpath/gnu/javax/activation/viewers/TextEditor.java @@ -0,0 +1,119 @@ +/* TextEditor.java -- Simple text editor component. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.activation.viewers; + +import java.awt.Dimension; +import java.awt.TextArea; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import javax.activation.CommandObject; +import javax.activation.DataHandler; + +/** + * Simple text editor component. + * + * @author Chris Burdess + * @version 1.0.2 + */ +public class TextEditor extends TextArea + implements CommandObject, ActionListener +{ + + private transient DataHandler dh; + + public TextEditor() + { + super("", 24, 80, 1); + } + + public Dimension getPreferredSize() + { + return getMinimumSize(24, 80); + } + + public void setCommandContext(String verb, DataHandler dh) + throws IOException + { + this.dh = dh; + InputStream in = dh.getInputStream(); + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + byte[] buf = new byte[4096]; + for (int len = in.read(buf); len != -1; len = in.read(buf)) + bytes.write(buf, 0, len); + in.close(); + setText(bytes.toString()); + } + + public void actionPerformed(ActionEvent event) + { + if ("save".equals(event.getActionCommand()) && dh != null) + { + OutputStream out = null; + try + { + out = dh.getOutputStream(); + if (out != null) + out.write(getText().getBytes()); + } + catch (IOException e) + { + e.printStackTrace(System.err); + } + finally + { + if (out != null) + { + try + { + + out.close(); + } + catch (IOException e) + { + e.printStackTrace(System.err); + } + } + } + } + } + +} diff --git a/libjava/classpath/gnu/javax/activation/viewers/TextViewer.java b/libjava/classpath/gnu/javax/activation/viewers/TextViewer.java new file mode 100644 index 000000000..deac80d5e --- /dev/null +++ b/libjava/classpath/gnu/javax/activation/viewers/TextViewer.java @@ -0,0 +1,81 @@ +/* TextViewer.java -- Simple text viewer component. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.activation.viewers; + +import java.awt.Dimension; +import java.awt.TextArea; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.IOException; +import javax.activation.CommandObject; +import javax.activation.DataHandler; + +/** + * Simple text display component. + * + * @author Chris Burdess + * @version 1.0.2 + */ +public class TextViewer extends TextArea + implements CommandObject +{ + + public TextViewer() + { + super("", 24, 80, 1); + setEditable(false); + } + + public Dimension getPreferredSize() + { + return getMinimumSize(24, 80); + } + + public void setCommandContext(String verb, DataHandler dh) + throws IOException + { + InputStream in = dh.getInputStream(); + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + byte[] buf = new byte[4096]; + for (int len = in.read(buf); len != -1; len = in.read(buf)) + bytes.write(buf, 0, len); + in.close(); + setText(bytes.toString()); + } + +} diff --git a/libjava/classpath/gnu/javax/crypto/RSACipherImpl.java b/libjava/classpath/gnu/javax/crypto/RSACipherImpl.java new file mode 100644 index 000000000..a4adff007 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/RSACipherImpl.java @@ -0,0 +1,299 @@ +/* RSACipherImpl.java -- + Copyright (C) 2005, 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package 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; +import java.security.AlgorithmParameters; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.interfaces.RSAKey; +import java.security.interfaces.RSAPrivateCrtKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.AlgorithmParameterSpec; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.CipherSpi; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.ShortBufferException; + +public class RSACipherImpl + extends CipherSpi +{ + private static final SystemLogger logger = SystemLogger.SYSTEM; + + private static final byte[] EMPTY = new byte[0]; + private int opmode = -1; + private RSAPrivateKey decipherKey = null; + private RSAPublicKey blindingKey = null; + private RSAPublicKey encipherKey = null; + private SecureRandom random = null; + private byte[] dataBuffer = null; + private int pos = 0; + + protected void engineSetMode(String mode) throws NoSuchAlgorithmException + { + throw new NoSuchAlgorithmException("only one mode available"); + } + + protected void engineSetPadding(String pad) throws NoSuchPaddingException + { + throw new NoSuchPaddingException("only one padding available"); + } + + protected int engineGetBlockSize() + { + return 1; + } + + protected int engineGetOutputSize(int inputLen) + { + int outputLen = 0; + if (decipherKey != null) + outputLen = (decipherKey.getModulus().bitLength() + 7) / 8; + else if (encipherKey != null) + outputLen = (encipherKey.getModulus().bitLength() + 7) / 8; + else + throw new IllegalStateException("not initialized"); + if (inputLen > outputLen) + throw new IllegalArgumentException("not configured to encode " + inputLen + + "bytes; at most " + outputLen); + return outputLen; + } + + protected int engineGetKeySize(final Key key) throws InvalidKeyException + { + if (! (key instanceof RSAKey)) + throw new InvalidKeyException("not an RSA key"); + return ((RSAKey) key).getModulus().bitLength(); + } + + protected byte[] engineGetIV() + { + return null; + } + + protected AlgorithmParameters engineGetParameters() + { + return null; + } + + protected void engineInit(int opmode, Key key, SecureRandom random) + throws InvalidKeyException + { + int outputLen = 0; + if (opmode == Cipher.ENCRYPT_MODE) + { + if (! (key instanceof RSAPublicKey)) + throw new InvalidKeyException("expecting a RSAPublicKey"); + encipherKey = (RSAPublicKey) key; + decipherKey = null; + blindingKey = null; + outputLen = (encipherKey.getModulus().bitLength() + 7) / 8; + } + else if (opmode == Cipher.DECRYPT_MODE) + { + if (key instanceof RSAPrivateKey) + { + decipherKey = (RSAPrivateKey) key; + encipherKey = null; + blindingKey = null; + outputLen = (decipherKey.getModulus().bitLength() + 7) / 8; + } + else if (key instanceof RSAPublicKey) + { + if (decipherKey == null) + throw new IllegalStateException("must configure decryption key first"); + if (! decipherKey.getModulus().equals(((RSAPublicKey) key).getModulus())) + throw new InvalidKeyException("blinding key is not compatible"); + blindingKey = (RSAPublicKey) key; + return; + } + else + throw new InvalidKeyException( + "expecting either an RSAPrivateKey or an RSAPublicKey (for blinding)"); + } + else + throw new IllegalArgumentException("only encryption and decryption supported"); + this.random = random; + this.opmode = opmode; + pos = 0; + dataBuffer = new byte[outputLen]; + } + + protected void engineInit(int opmode, Key key, AlgorithmParameterSpec spec, + SecureRandom random) throws InvalidKeyException + { + engineInit(opmode, key, random); + } + + protected void engineInit(int opmode, Key key, AlgorithmParameters params, + SecureRandom random) throws InvalidKeyException + { + engineInit(opmode, key, random); + } + + protected byte[] engineUpdate(byte[] in, int offset, int length) + { + if (opmode != Cipher.ENCRYPT_MODE && opmode != Cipher.DECRYPT_MODE) + throw new IllegalStateException("not initialized"); + System.arraycopy(in, offset, dataBuffer, pos, length); + pos += length; + return EMPTY; + } + + protected int engineUpdate(byte[] in, int offset, int length, byte[] out, + int outOffset) + { + engineUpdate(in, offset, length); + return 0; + } + + protected byte[] engineDoFinal(byte[] in, int offset, int length) + throws IllegalBlockSizeException, BadPaddingException + { + engineUpdate(in, offset, length); + if (opmode == Cipher.DECRYPT_MODE) + { + 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 + { + offset = dataBuffer.length - pos; + if (offset < 3) + throw new IllegalBlockSizeException("input is too large to encrypt"); + EME_PKCS1_V1_5 pkcs = EME_PKCS1_V1_5.getInstance(encipherKey); + if (random == null) + random = new SecureRandom(); + 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]; + System.arraycopy(enc, 1, tmp, 0, tmp.length); + enc = tmp; + } + pos = 0; + return enc; + } + } + + protected int engineDoFinal(byte[] out, int offset) + throws ShortBufferException, IllegalBlockSizeException, + BadPaddingException + { + byte[] result = engineDoFinal(EMPTY, 0, 0); + if (out.length - offset < result.length) + throw new ShortBufferException("need " + result.length + ", have " + + (out.length - offset)); + System.arraycopy(result, 0, out, offset, result.length); + return result.length; + } + + protected int engineDoFinal(final byte[] input, final int offset, + final int length, final byte[] output, + final int outputOffset) + throws ShortBufferException, IllegalBlockSizeException, + BadPaddingException + { + byte[] result = engineDoFinal(input, offset, length); + if (output.length - outputOffset < result.length) + throw new ShortBufferException("need " + result.length + ", have " + + (output.length - outputOffset)); + System.arraycopy(result, 0, output, outputOffset, result.length); + return result.length; + } + + /** + * Decrypts the ciphertext, employing RSA blinding if possible. + */ + private byte[] rsaDecrypt(BigInteger enc) + { + if (random == null) + random = new SecureRandom(); + BigInteger n = decipherKey.getModulus(); + BigInteger r = null; + BigInteger pubExp = null; + if (blindingKey != null) + pubExp = blindingKey.getPublicExponent(); + if (pubExp != null && (decipherKey instanceof RSAPrivateCrtKey)) + pubExp = ((RSAPrivateCrtKey) decipherKey).getPublicExponent(); + if (pubExp != null) + { + r = new BigInteger(n.bitLength() - 1, random); + enc = r.modPow(pubExp, n).multiply(enc).mod(n); + } + BigInteger dec = enc.modPow(decipherKey.getPrivateExponent(), n); + if (pubExp != null) + { + 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/libjava/classpath/gnu/javax/crypto/assembly/Assembly.java b/libjava/classpath/gnu/javax/crypto/assembly/Assembly.java new file mode 100644 index 000000000..f570d2012 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/Assembly.java @@ -0,0 +1,272 @@ +/* Assembly.java -- + Copyright (C) 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.crypto.assembly; + +import java.util.Map; + +/** + * An Assembly is a construction consisting of a chain of + * {@link Transformer} elements; each wired in pre- or post- transformation + * mode. This chain is terminated by one LoopbackTransformer + * element. + *

+ * Once constructed, and correctly initialised, the bulk of the methods + * available on the Assembly are delegated to the head of + * the {@link Transformer} chain of the Assembly. + * + * @see Transformer + */ +public class Assembly +{ + public static final String DIRECTION = "gnu.crypto.assembly.assembly.direction"; + + /** Flag that tells if the instance is initialised or not; and if yes how. */ + private Direction wired; + + /** The first Transformer in the chain. */ + private Transformer head; + + /** + * Trivial constructor that sets the chain to a + * LoopbackTransformer. + */ + public Assembly() + { + super(); + + wired = null; + head = new LoopbackTransformer(); + } + + /** + * Adds the designated {@link Transformer} and signals that it should operate + * in pre-processing mode; i.e. it should apply its internal transformation + * algorithm on the input data stream, before it passes that stream to + * the next element in the chain. + * + * @param t the {@link Transformer} to add at the head of the current chain. + * @throws IllegalArgumentException if the designated {@link Transformer} has + * a non-null tail; i.e. it is already an element of a chain. + */ + public void addPreTransformer(Transformer t) + { + wireTransformer(t, Operation.PRE_PROCESSING); + } + + /** + * Adds the designated {@link Transformer} and signals that it should operate + * in post-processing mode; i.e. it should apply its internal transformation + * algorithm on the input data stream, after it passes that stream to + * the next element in the chain. + * + * @param t the {@link Transformer} to add at the head of the current chain. + * @throws IllegalArgumentException if the designated {@link Transformer} has + * a non-null tail; i.e. it is already an element of a chain. + */ + public void addPostTransformer(Transformer t) + { + wireTransformer(t, Operation.POST_PROCESSING); + } + + /** + * Initialises the Assembly for operation with specific + * characteristics. + * + * @param attributes a set of name-value pairs that describes the desired + * future behaviour of this instance. + * @throws IllegalStateException if the instance is already initialised. + */ + public void init(Map attributes) throws TransformerException + { + if (wired != null) + throw new IllegalStateException(); + Direction flow = (Direction) attributes.get(DIRECTION); + if (flow == null) + flow = Direction.FORWARD; + attributes.put(Transformer.DIRECTION, flow); + head.init(attributes); + wired = flow; + } + + /** + * Resets the Assembly for re-initialisation and use with other + * characteristics. This method always succeeds. + */ + public void reset() + { + head.reset(); + wired = null; + } + + /** + * Convenience method that calls the method with same name and three + * arguments, using a byte array of length 1 whose contents are + * the designated byte. + * + * @param b the byte to process. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + * @see #update(byte[], int, int) + */ + public byte[] update(byte b) throws TransformerException + { + return update(new byte[] { b }, 0, 1); + } + + /** + * Convenience method that calls the method with same name and three + * arguments. All bytes in in, starting from index position + * 0 are considered. + * + * @param in the input data bytes. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + * @see #update(byte[], int, int) + */ + public byte[] update(byte[] in) throws TransformerException + { + return update(in, 0, in.length); + } + + /** + * Processes a designated number of bytes from a given byte array. + * + * @param in the input data bytes. + * @param offset index of in from which to start considering + * data. + * @param length the count of bytes to process. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + */ + public byte[] update(byte[] in, int offset, int length) + throws TransformerException + { + if (wired == null) + throw new IllegalStateException(); + return head.update(in, offset, length); + } + + /** + * Convenience method that calls the method with same name and three arguments + * using a 0-long byte array. + * + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + * @see #lastUpdate(byte[], int, int) + */ + public byte[] lastUpdate() throws TransformerException + { + return lastUpdate(new byte[0], 0, 0); + } + + /** + * Convenience method that calls the method with same name and three + * arguments, using a byte array of length 1 whose contents are + * the designated byte. + * + * @param b the byte to process. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + * @see #lastUpdate(byte[], int, int) + */ + public byte[] lastUpdate(byte b) throws TransformerException + { + return lastUpdate(new byte[] { b }, 0, 1); + } + + /** + * Convenience method that calls the method with same name and three + * arguments. All bytes in in, starting from index position + * 0 are considered. + * + * @param in the input data bytes. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + * @see #lastUpdate(byte[], int, int) + */ + public byte[] lastUpdate(byte[] in) throws TransformerException + { + return lastUpdate(in, 0, in.length); + } + + /** + * Processes a designated number of bytes from a given byte array and signals, + * at the same time, that this is the last push operation for this + * Assembly. + * + * @param in the input data bytes. + * @param offset index of in from which to start considering + * data. + * @param length the count of bytes to process. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + */ + public byte[] lastUpdate(byte[] in, int offset, int length) + throws TransformerException + { + if (wired == null) + throw new IllegalStateException(); + byte[] result = head.lastUpdate(in, offset, length); + reset(); + return result; + } + + private void wireTransformer(Transformer t, Operation mode) + { + if (t.tail != null) + throw new IllegalArgumentException(); + t.setMode(mode); + t.tail = head; + head = t; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/assembly/Cascade.java b/libjava/classpath/gnu/javax/crypto/assembly/Cascade.java new file mode 100644 index 000000000..685cef5b2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/Cascade.java @@ -0,0 +1,348 @@ +/* Cascade.java -- + Copyright (C) 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.crypto.assembly; + +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Map; +import java.util.Set; + +/** + * A Cascade Cipher is the concatenation of two or more block ciphers + * each with independent keys. Plaintext is input to the first stage; the output + * of stage i is input to stage i + 1; and the + * output of the last stage is the Cascade's ciphertext output. + *

+ * In the simplest case, all stages in a Cascade have k-bit + * keys, and the stage inputs and outputs are all n-bit quantities. The stage + * ciphers may differ (general cascade of ciphers), or all be identical (cascade + * of identical ciphers). + *

+ * The term "block ciphers" used above refers to implementations of + * {@link gnu.javax.crypto.mode.IMode}, including the + * {@link gnu.javax.crypto.mode.ECB} mode which basically exposes a + * symmetric-key block cipher algorithm as a Mode of Operations. + *

+ * References: + *

    + *
  1. [HAC]: Handbook of + * Applied Cryptography.
    + * CRC Press, Inc. ISBN 0-8493-8523-7, 1997
    + * Menezes, A., van Oorschot, P. and S. Vanstone.
  2. + *
+ */ +public class Cascade +{ + public static final String DIRECTION = "gnu.crypto.assembly.cascade.direction"; + + /** The map of Stages chained in this cascade. */ + protected HashMap stages; + + /** The ordered list of Stage UIDs to their attribute maps. */ + protected LinkedList stageKeys; + + /** The current operational direction of this instance. */ + protected Direction wired; + + /** The curently set block-size for this instance. */ + protected int blockSize; + + public Cascade() + { + super(); + + stages = new HashMap(3); + stageKeys = new LinkedList(); + wired = null; + blockSize = 0; + } + + /** + * Returns the Least Common Multiple of two integers. + * + * @param a the first integer. + * @param b the second integer. + * @return the LCM of abs(a) and abs(b). + */ + private static final int lcm(int a, int b) + { + BigInteger A = BigInteger.valueOf(a * 1L); + BigInteger B = BigInteger.valueOf(b * 1L); + return A.multiply(B).divide(A.gcd(B)).abs().intValue(); + } + + /** + * Adds to the end of the current chain, a designated {@link Stage}. + * + * @param stage the {@link Stage} to append to the chain. + * @return a unique identifier for this stage, within this cascade. + * @throws IllegalStateException if the instance is already initialised. + * @throws IllegalArgumentException if the designated stage is already in the + * chain, or it has incompatible characteristics with the current + * elements already in the chain. + */ + public Object append(Stage stage) throws IllegalArgumentException + { + return insert(size(), stage); + } + + /** + * Adds to the begining of the current chain, a designated {@link Stage}. + * + * @param stage the {@link Stage} to prepend to the chain. + * @return a unique identifier for this stage, within this cascade. + * @throws IllegalStateException if the instance is already initialised. + * @throws IllegalArgumentException if the designated stage is already in the + * chain, or it has incompatible characteristics with the current + * elements already in the chain. + */ + public Object prepend(Stage stage) throws IllegalArgumentException + { + return insert(0, stage); + } + + /** + * Inserts a {@link Stage} into the current chain, at the specified index + * (zero-based) position. + * + * @param stage the {@link Stage} to insert into the chain. + * @return a unique identifier for this stage, within this cascade. + * @throws IllegalArgumentException if the designated stage is already in the + * chain, or it has incompatible characteristics with the current + * elements already in the chain. + * @throws IllegalStateException if the instance is already initialised. + * @throws IndexOutOfBoundsException if index is less than + * 0 or greater than the current size of this + * cascade. + */ + public Object insert(int index, Stage stage) throws IllegalArgumentException, + IndexOutOfBoundsException + { + if (stages.containsValue(stage)) + throw new IllegalArgumentException(); + if (wired != null || stage == null) + throw new IllegalStateException(); + if (index < 0 || index > size()) + throw new IndexOutOfBoundsException(); + // check that there is a non-empty set of common block-sizes + Set set = stage.blockSizes(); + if (stages.isEmpty()) + { + if (set.isEmpty()) + throw new IllegalArgumentException("1st stage with no block sizes"); + } + else + { + Set common = this.blockSizes(); + common.retainAll(set); + if (common.isEmpty()) + throw new IllegalArgumentException("no common block sizes found"); + } + Object result = new Object(); + stageKeys.add(index, result); + stages.put(result, stage); + return result; + } + + /** + * Returns the current number of stages in this chain. + * + * @return the current count of stages in this chain. + */ + public int size() + { + return stages.size(); + } + + /** + * Returns an {@link Iterator} over the stages contained in this instance. + * Each element of this iterator is a concrete implementation of a {@link + * Stage}. + * + * @return an {@link Iterator} over the stages contained in this instance. + * Each element of the returned iterator is a concrete instance of a + * {@link Stage}. + */ + public Iterator stages() + { + LinkedList result = new LinkedList(); + for (Iterator it = stageKeys.listIterator(); it.hasNext();) + result.addLast(stages.get(it.next())); + return result.listIterator(); + } + + /** + * Returns the {@link Set} of supported block sizes for this + * Cascade that are common to all of its chained stages. Each + * element in the returned {@link Set} is an instance of {@link Integer}. + * + * @return a {@link Set} of supported block sizes common to all the stages of + * the chain. + */ + public Set blockSizes() + { + HashSet result = null; + for (Iterator it = stages.values().iterator(); it.hasNext();) + { + Stage aStage = (Stage) it.next(); + if (result == null) // first time + result = new HashSet(aStage.blockSizes()); + else + result.retainAll(aStage.blockSizes()); + } + return result == null ? Collections.EMPTY_SET : result; + } + + /** + * Initialises the chain for operation with specific characteristics. + * + * @param attributes a set of name-value pairs that describes the desired + * future behaviour of this instance. + * @throws IllegalStateException if the chain, or any of its stages, is + * already initialised. + * @throws InvalidKeyException if the intialisation data provided with the + * stage is incorrect or causes an invalid key to be generated. + * @see Direction#FORWARD + * @see Direction#REVERSED + */ + public void init(Map attributes) throws InvalidKeyException + { + if (wired != null) + throw new IllegalStateException(); + Direction flow = (Direction) attributes.get(DIRECTION); + if (flow == null) + flow = Direction.FORWARD; + int optimalSize = 0; + for (Iterator it = stageKeys.listIterator(); it.hasNext();) + { + Object id = it.next(); + Map attr = (Map) attributes.get(id); + attr.put(Stage.DIRECTION, flow); + Stage stage = (Stage) stages.get(id); + stage.init(attr); + optimalSize = optimalSize == 0 ? stage.currentBlockSize() + : lcm(optimalSize, + stage.currentBlockSize()); + } + if (flow == Direction.REVERSED) // reverse order + Collections.reverse(stageKeys); + wired = flow; + blockSize = optimalSize; + } + + /** + * Returns the currently set block size for the chain. + * + * @return the current block size for the chain. + * @throws IllegalStateException if the instance is not initialised. + */ + public int currentBlockSize() + { + if (wired == null) + throw new IllegalStateException(); + return blockSize; + } + + /** + * Resets the chain for re-initialisation and use with other characteristics. + * This method always succeeds. + */ + public void reset() + { + for (Iterator it = stageKeys.listIterator(); it.hasNext();) + ((Stage) stages.get(it.next())).reset(); + if (wired == Direction.REVERSED) // reverse it back + Collections.reverse(stageKeys); + wired = null; + blockSize = 0; + } + + /** + * Processes exactly one block of plaintext (if initialised in the + * {@link Direction#FORWARD} state) or ciphertext (if initialised in + * the {@link Direction#REVERSED} state). + * + * @param in the plaintext. + * @param inOffset index of in from which to start considering + * data. + * @param out the ciphertext. + * @param outOffset index of out from which to store result. + * @throws IllegalStateException if the instance is not initialised. + */ + public void update(byte[] in, int inOffset, byte[] out, int outOffset) + { + if (wired == null) + throw new IllegalStateException(); + int stageBlockSize, j, i = stages.size(); + for (Iterator it = stageKeys.listIterator(); it.hasNext();) + { + Stage stage = (Stage) stages.get(it.next()); + stageBlockSize = stage.currentBlockSize(); + for (j = 0; j < blockSize; j += stageBlockSize) + stage.update(in, inOffset + j, out, outOffset + j); + i--; + if (i > 0) + System.arraycopy(out, outOffset, in, inOffset, blockSize); + } + } + + /** + * Conducts a simple correctness test that consists of basic symmetric + * encryption / decryption test(s) for all supported block and key sizes of + * underlying block cipher(s) wrapped by Mode leafs. The test also includes + * one (1) variable key Known Answer Test (KAT) for each block cipher. + * + * @return true if the implementation passes simple + * correctness tests. Returns false otherwise. + */ + public boolean selfTest() + { + for (Iterator it = stageKeys.listIterator(); it.hasNext();) + { + if (! ((Stage) stages.get(it.next())).selfTest()) + return false; + } + return true; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/assembly/CascadeStage.java b/libjava/classpath/gnu/javax/crypto/assembly/CascadeStage.java new file mode 100644 index 000000000..196edafdf --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/CascadeStage.java @@ -0,0 +1,93 @@ +/* CascadeStage.java -- + Copyright (C) 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.crypto.assembly; + +import java.security.InvalidKeyException; +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +/** + * A Cascade Stage in a Cascade Cipher. + */ +class CascadeStage + extends Stage +{ + private Cascade delegate; + + CascadeStage(Cascade cascade, Direction forwardDirection) + { + super(forwardDirection); + + this.delegate = cascade; + } + + public Set blockSizes() + { + return Collections.unmodifiableSet(delegate.blockSizes()); + } + + void initDelegate(Map attributes) throws InvalidKeyException + { + Direction flow = (Direction) attributes.get(DIRECTION); + attributes.put(DIRECTION, flow.equals(forward) ? forward + : Direction.reverse(forward)); + delegate.init(attributes); + } + + public int currentBlockSize() throws IllegalStateException + { + return delegate.currentBlockSize(); + } + + void resetDelegate() + { + delegate.reset(); + } + + void updateDelegate(byte[] in, int inOffset, byte[] out, int outOffset) + { + delegate.update(in, inOffset, out, outOffset); + } + + public boolean selfTest() + { + return delegate.selfTest(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/assembly/CascadeTransformer.java b/libjava/classpath/gnu/javax/crypto/assembly/CascadeTransformer.java new file mode 100644 index 000000000..8e3a9a5a1 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/CascadeTransformer.java @@ -0,0 +1,123 @@ +/* CascadeTransformer.java -- + Copyright (C) 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.crypto.assembly; + +import java.security.InvalidKeyException; +import java.util.Map; + +/** + * An Adapter to use any {@link Cascade} as a {@link Transformer} in an + * {@link Assembly}. + */ +class CascadeTransformer + extends Transformer +{ + private Cascade delegate; + + private int blockSize; + + CascadeTransformer(Cascade delegate) + { + super(); + + this.delegate = delegate; + } + + void initDelegate(Map attributes) throws TransformerException + { + attributes.put(Cascade.DIRECTION, wired); + try + { + delegate.init(attributes); + } + catch (InvalidKeyException x) + { + throw new TransformerException("initDelegate()", x); + } + blockSize = delegate.currentBlockSize(); + } + + int delegateBlockSize() + { + return blockSize; + } + + void resetDelegate() + { + delegate.reset(); + blockSize = 0; + } + + byte[] updateDelegate(byte[] in, int offset, int length) + throws TransformerException + { + byte[] result = updateInternal(in, offset, length); + return result; + } + + byte[] lastUpdateDelegate() throws TransformerException + { + if (inBuffer.size() != 0) + { + IllegalStateException cause = new IllegalStateException( + "Cascade transformer, after last update, must be empty but isn't"); + throw new TransformerException("lastUpdateDelegate()", cause); + } + return new byte[0]; + } + + private byte[] updateInternal(byte[] in, int offset, int length) + { + byte[] result; + for (int i = 0; i < length; i++) + { + inBuffer.write(in[offset++] & 0xFF); + if (inBuffer.size() >= blockSize) + { + result = inBuffer.toByteArray(); + inBuffer.reset(); + delegate.update(result, 0, result, 0); + outBuffer.write(result, 0, blockSize); + } + } + result = outBuffer.toByteArray(); + outBuffer.reset(); + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/assembly/DeflateTransformer.java b/libjava/classpath/gnu/javax/crypto/assembly/DeflateTransformer.java new file mode 100644 index 000000000..97f9f0365 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/DeflateTransformer.java @@ -0,0 +1,177 @@ +/* DeflateTransformer.java -- + Copyright (C) 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.crypto.assembly; + +import java.util.Map; +import java.util.zip.DataFormatException; +import java.util.zip.Deflater; +import java.util.zip.Inflater; + +/** + * A {@link Transformer} Adapter allowing inclusion of a DEFLATE compression + * algorithm in an {@link Assembly} chain. The {@link Direction#FORWARD} + * transformation is a compression (deflate) of input data, while the + * {@link Direction#REVERSED} one is a decompression (inflate) that restores the + * original data. + *

+ * This {@link Transformer} uses a {@link Deflater} instance to carry on the + * compression, and an {@link Inflater} to do the decompression. + *

+ * When using such a {@link Transformer}, in an {@link Assembly}, there must + * be at least one element behind this instance in the constructed chain; + * otherwise, a {@link TransformerException} is thrown at initialisation time. + */ +class DeflateTransformer + extends Transformer +{ + private Deflater compressor; + + private Inflater decompressor; + + private int outputBlockSize = 512; // default zlib buffer size + + private byte[] zlibBuffer; + + DeflateTransformer() + { + super(); + + } + + void initDelegate(Map attributes) throws TransformerException + { + if (tail == null) + { + IllegalStateException cause = new IllegalStateException( + "Compression transformer missing its tail!"); + throw new TransformerException("initDelegate()", cause); + } + outputBlockSize = tail.currentBlockSize(); + zlibBuffer = new byte[outputBlockSize]; + Direction flow = (Direction) attributes.get(DIRECTION); + if (flow == Direction.FORWARD) + compressor = new Deflater(); + else + decompressor = new Inflater(); + } + + int delegateBlockSize() + { + return 1; + } + + void resetDelegate() + { + compressor = null; + decompressor = null; + outputBlockSize = 1; + zlibBuffer = null; + } + + byte[] updateDelegate(byte[] in, int offset, int length) + throws TransformerException + { + byte[] result; + if (wired == Direction.FORWARD) + { + compressor.setInput(in, offset, length); + while (! compressor.needsInput()) + compress(); + } + else // decompression: inflate first and then update tail + decompress(in, offset, length); + result = inBuffer.toByteArray(); + inBuffer.reset(); + return result; + } + + byte[] lastUpdateDelegate() throws TransformerException + { + // process multiples of blocksize as much as possible + if (wired == Direction.FORWARD) // compressing + { + if (! compressor.finished()) + { + compressor.finish(); + while (! compressor.finished()) + compress(); + } + } + else // decompressing + { + if (! decompressor.finished()) + { + IllegalStateException cause = new IllegalStateException( + "Compression transformer, after last update, must be finished " + + "but isn't"); + throw new TransformerException("lastUpdateDelegate()", cause); + } + } + byte[] result = inBuffer.toByteArray(); + inBuffer.reset(); + return result; + } + + private void compress() + { + int len = compressor.deflate(zlibBuffer); + if (len > 0) + inBuffer.write(zlibBuffer, 0, len); + } + + private void decompress(byte[] in, int offset, int length) + throws TransformerException + { + decompressor.setInput(in, offset, length); + int len = 1; + while (len > 0) + { + try + { + len = decompressor.inflate(zlibBuffer); + } + catch (DataFormatException x) + { + throw new TransformerException("decompress()", x); + } + if (len > 0) + inBuffer.write(zlibBuffer, 0, len); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/assembly/Direction.java b/libjava/classpath/gnu/javax/crypto/assembly/Direction.java new file mode 100644 index 000000000..40ddfc429 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/Direction.java @@ -0,0 +1,78 @@ +/* Direction.java -- + Copyright (C) 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.crypto.assembly; + +/** + * An enumeration type for wiring {@link Stage} instances into {@link Cascade} + * Cipher chains, as well as for operating a {@link Cascade} in a given + * direction. + *

+ * The possible values for this type are two: + *

    + *
  1. FORWARD: equivalent to {@link gnu.javax.crypto.mode.IMode#ENCRYPTION}, + * and its inverse value
  2. + *
  3. REVERSED: equivalent to {@link gnu.javax.crypto.mode.IMode#DECRYPTION}. + *
  4. + *
+ */ +public final class Direction +{ + public static final Direction FORWARD = new Direction(1); + + public static final Direction REVERSED = new Direction(2); + + private int value; + + private Direction(int value) + { + super(); + + this.value = value; + } + + public static final Direction reverse(Direction d) + { + return (d.equals(FORWARD) ? REVERSED : FORWARD); + } + + public String toString() + { + return (this == FORWARD ? "forward" : "reversed"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/assembly/LoopbackTransformer.java b/libjava/classpath/gnu/javax/crypto/assembly/LoopbackTransformer.java new file mode 100644 index 000000000..5bcfe5ffc --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/LoopbackTransformer.java @@ -0,0 +1,100 @@ +/* LoopbackTransformer.java -- + Copyright (C) 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.crypto.assembly; + +import java.util.Map; + +/** + * A trivial {@link Transformer} to allow closing a chain in an {@link Assembly}. + * This class is not visible outside this package. + */ +final class LoopbackTransformer + extends Transformer +{ + /** Trivial package-private constructor. */ + LoopbackTransformer() + { + super(); + } + + public void init(Map attributes) throws TransformerException + { + } + + public void reset() + { + } + + public byte[] update(byte[] in, int offset, int length) + throws TransformerException + { + return updateDelegate(in, offset, length); + } + + public byte[] lastUpdate() throws TransformerException + { + return lastUpdateDelegate(); + } + + void initDelegate(Map attributes) throws TransformerException + { + } + + int delegateBlockSize() + { + return 1; + } + + void resetDelegate() + { + } + + byte[] updateDelegate(byte[] in, int offset, int length) + throws TransformerException + { + byte[] result = new byte[length]; + System.arraycopy(in, offset, result, 0, length); + return result; + } + + byte[] lastUpdateDelegate() throws TransformerException + { + return new byte[0]; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/assembly/ModeStage.java b/libjava/classpath/gnu/javax/crypto/assembly/ModeStage.java new file mode 100644 index 000000000..8bdbef7c4 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/ModeStage.java @@ -0,0 +1,112 @@ +/* ModeStage.java -- + Copyright (C) 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.crypto.assembly; + +import gnu.javax.crypto.mode.IMode; + +import java.security.InvalidKeyException; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + * An {@link IMode} {@link Stage} in a {@link Cascade} Cipher chain. + *

+ * Such a stage wraps an implementation of a Block Cipher Mode of Operation + * ({@link IMode}) to allow inclusion of such an instance in a cascade of block + * ciphers. + */ +class ModeStage + extends Stage +{ + private IMode delegate; + + private transient Set cachedBlockSizes; + + ModeStage(IMode mode, Direction forwardDirection) + { + super(forwardDirection); + + delegate = mode; + cachedBlockSizes = null; + } + + public Set blockSizes() + { + if (cachedBlockSizes == null) + { + HashSet result = new HashSet(); + for (Iterator it = delegate.blockSizes(); it.hasNext();) + result.add(it.next()); + cachedBlockSizes = Collections.unmodifiableSet(result); + } + return cachedBlockSizes; + } + + void initDelegate(Map attributes) throws InvalidKeyException + { + Direction flow = (Direction) attributes.get(DIRECTION); + attributes.put(IMode.STATE, + Integer.valueOf(flow.equals(forward) ? IMode.ENCRYPTION + : IMode.DECRYPTION)); + delegate.init(attributes); + } + + public int currentBlockSize() throws IllegalStateException + { + return delegate.currentBlockSize(); + } + + void resetDelegate() + { + delegate.reset(); + } + + void updateDelegate(byte[] in, int inOffset, byte[] out, int outOffset) + { + delegate.update(in, inOffset, out, outOffset); + } + + public boolean selfTest() + { + return delegate.selfTest(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/assembly/Operation.java b/libjava/classpath/gnu/javax/crypto/assembly/Operation.java new file mode 100644 index 000000000..6861a1377 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/Operation.java @@ -0,0 +1,73 @@ +/* Operation.java -- + Copyright (C) 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.crypto.assembly; + +/** + * An enumeration type for specifying the operation type of a + * {@link Transformer}. + *

+ * The possible values for this type are two: + *

    + *
  1. PRE_PROCESSING: where the input data is first processed by the current + * {@link Transformer} before being passed to the rest of the chain; and
  2. + *
  3. POST_PROCESSING: where the input data is first passed to the rest of the + * chain, and the resulting bytes are then processed by the current + * {@link Transformer}.
  4. + *
+ */ +public final class Operation +{ + public static final Operation PRE_PROCESSING = new Operation(1); + + public static final Operation POST_PROCESSING = new Operation(2); + + private int value; + + private Operation(int value) + { + super(); + + this.value = value; + } + + public String toString() + { + return (this == PRE_PROCESSING ? "pre-processing" : "post-processing"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/assembly/PaddingTransformer.java b/libjava/classpath/gnu/javax/crypto/assembly/PaddingTransformer.java new file mode 100644 index 000000000..494ca34ca --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/PaddingTransformer.java @@ -0,0 +1,164 @@ +/* PaddingTransformer.java -- + Copyright (C) 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.crypto.assembly; + +import gnu.javax.crypto.pad.IPad; +import gnu.javax.crypto.pad.WrongPaddingException; + +import java.util.Map; + +/** + * An Adapter to use any {@link IPad} as a {@link Transformer} in an + * {@link Assembly}. + *

+ * When using such a {@link Transformer}, in an {@link Assembly}, there must + * be at least one element behind this instance in the constructed chain; + * otherwise, a {@link TransformerException} is thrown at initialisation time. + */ +class PaddingTransformer + extends Transformer +{ + private IPad delegate; + + private int outputBlockSize = 1; + + PaddingTransformer(IPad padding) + { + super(); + + this.delegate = padding; + } + + void initDelegate(Map attributes) throws TransformerException + { + if (tail == null) + { + IllegalStateException cause = new IllegalStateException( + "Padding transformer missing its tail!"); + throw new TransformerException("initDelegate()", cause); + } + outputBlockSize = tail.currentBlockSize(); + delegate.init(outputBlockSize); + } + + int delegateBlockSize() + { + return outputBlockSize; + } + + void resetDelegate() + { + delegate.reset(); + outputBlockSize = 1; + } + + byte[] updateDelegate(byte[] in, int offset, int length) + throws TransformerException + { + inBuffer.write(in, offset, length); + byte[] tmp = inBuffer.toByteArray(); + inBuffer.reset(); + byte[] result; + if (wired == Direction.FORWARD) // padding + { + // buffers remaining bytes from (inBuffer + in) that are less than 1 + // block + if (tmp.length < outputBlockSize) + { + inBuffer.write(tmp, 0, tmp.length); + result = new byte[0]; + } + else + { + int newlen = outputBlockSize * (tmp.length / outputBlockSize); + inBuffer.write(tmp, newlen, tmp.length - newlen); + result = new byte[newlen]; + System.arraycopy(tmp, 0, result, 0, newlen); + } + } + else // unpadding + { + // always keep in own buffer a max of 1 block to cater for lastUpdate + if (tmp.length < outputBlockSize) + { + inBuffer.write(tmp, 0, tmp.length); + result = new byte[0]; + } + else + { + result = new byte[tmp.length - outputBlockSize]; + System.arraycopy(tmp, 0, result, 0, result.length); + inBuffer.write(tmp, result.length, outputBlockSize); + } + } + return result; + } + + byte[] lastUpdateDelegate() throws TransformerException + { + byte[] result; + // process multiples of blocksize as much as possible + // catenate result from processing inBuffer with last-update( tail ) + if (wired == Direction.FORWARD) // padding + { + result = inBuffer.toByteArray(); + byte[] padding = delegate.pad(result, 0, result.length); + inBuffer.write(padding, 0, padding.length); + } + else // unpadding + { + byte[] tmp = inBuffer.toByteArray(); + inBuffer.reset(); + int realLength; + try + { + realLength = tmp.length; // should be outputBlockSize + realLength -= delegate.unpad(tmp, 0, tmp.length); + } + catch (WrongPaddingException x) + { + throw new TransformerException("lastUpdateDelegate()", x); + } + inBuffer.write(tmp, 0, realLength); + } + result = inBuffer.toByteArray(); + inBuffer.reset(); + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/assembly/Stage.java b/libjava/classpath/gnu/javax/crypto/assembly/Stage.java new file mode 100644 index 000000000..5d0ab5353 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/Stage.java @@ -0,0 +1,202 @@ +/* Stage.java -- + Copyright (C) 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.crypto.assembly; + +import gnu.javax.crypto.mode.IMode; + +import java.security.InvalidKeyException; +import java.util.Map; +import java.util.Set; + +/** + * A Stage in a Cascade Cipher. + *

+ * Each stage may be either an implementation of a Block Cipher Mode of + * Operation ({@link IMode}) or another Cascade Cipher ({@link Cascade}). + * Each stage has also a natural operational direction when constructed + * for inclusion within a {@link Cascade}. This natural direction + * dictates how data flows from one stage into another when stages are chained + * together in a cascade. One can think of a stage and its natural direction as + * the specification of how to wire the stage into the chain. The following + * diagrams may help understand the paradigme. The first shows two stages + * chained each with a {@link Direction#FORWARD} direction. + * + *

+ *            FORWARD         FORWARD
+ *        +------+       +-------+
+ *        |      |       |       |
+ *        |  +--in --+   |   +--in --+
+ *     ---+  | Stage |   |   | Stage |  +---
+ *           +--out--+   |   +--out--+  |
+ *               |       |       |      |
+ *               +-------+       +------+
+ * 
+ * + *

+ * The second diagram shows two stages, one in a {@link Direction#FORWARD} + * direction, while the other is wired in a {@link Direction#REVERSED} + * direction. + * + *

+ *            FORWARD         REVERSED
+ *        +------+               +------+
+ *        |      |               |      |
+ *        |  +--in --+       +--in --+  |
+ *     ---+  | Stage |       | Stage |  +---
+ *           +--out--+       +--out--+
+ *               |               |
+ *               +---------------+
+ * 
+ * + * @see ModeStage + * @see CascadeStage + */ +public abstract class Stage +{ + public static final String DIRECTION = "gnu.crypto.assembly.stage.direction"; + + protected Direction forward; + + protected Direction wired; + + protected Stage(Direction forwardDirection) + { + super(); + + this.forward = forwardDirection; + this.wired = null; + } + + public static final Stage getInstance(IMode mode, Direction forwardDirection) + { + return new ModeStage(mode, forwardDirection); + } + + public static final Stage getInstance(Cascade cascade, + Direction forwardDirection) + { + return new CascadeStage(cascade, forwardDirection); + } + + /** + * Returns the {@link Set} of supported block sizes for this + * Stage. Each element in the returned {@link Set} is an + * instance of {@link Integer}. + * + * @return a {@link Set} of supported block sizes. + */ + public abstract Set blockSizes(); + + /** + * Initialises the stage for operation with specific characteristics. + * + * @param attributes a set of name-value pairs that describes the desired + * future behaviour of this instance. + * @throws IllegalStateException if the instance is already initialised. + * @throws InvalidKeyException if the key data is invalid. + */ + public void init(Map attributes) throws InvalidKeyException + { + if (wired != null) + throw new IllegalStateException(); + Direction flow = (Direction) attributes.get(DIRECTION); + if (flow == null) + { + flow = Direction.FORWARD; + attributes.put(DIRECTION, flow); + } + initDelegate(attributes); + wired = flow; + } + + /** + * Returns the currently set block size for the stage. + * + * @return the current block size for this stage. + * @throws IllegalStateException if the instance is not initialised. + */ + public abstract int currentBlockSize() throws IllegalStateException; + + /** + * Resets the stage for re-initialisation and use with other characteristics. + * This method always succeeds. + */ + public void reset() + { + resetDelegate(); + wired = null; + } + + /** + * Processes exactly one block of plaintext (if initialised in the + * {@link Direction#FORWARD} state) or ciphertext (if initialised in + * the {@link Direction#REVERSED} state). + * + * @param in the plaintext. + * @param inOffset index of in from which to start considering + * data. + * @param out the ciphertext. + * @param outOffset index of out from which to store result. + * @throws IllegalStateException if the instance is not initialised. + */ + public void update(byte[] in, int inOffset, byte[] out, int outOffset) + { + if (wired == null) + throw new IllegalStateException(); + updateDelegate(in, inOffset, out, outOffset); + } + + /** + * Conducts a simple correctness test that consists of basic symmetric + * encryption / decryption test(s) for all supported block and key sizes of + * underlying block cipher(s) wrapped by Mode leafs. The test also includes + * one (1) variable key Known Answer Test (KAT) for each block cipher. + * + * @return true if the implementation passes simple + * correctness tests. Returns false otherwise. + */ + public abstract boolean selfTest(); + + abstract void initDelegate(Map attributes) throws InvalidKeyException; + + abstract void resetDelegate(); + + abstract void updateDelegate(byte[] in, int inOffset, byte[] out, + int outOffset); +} diff --git a/libjava/classpath/gnu/javax/crypto/assembly/Transformer.java b/libjava/classpath/gnu/javax/crypto/assembly/Transformer.java new file mode 100644 index 000000000..1937f9950 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/Transformer.java @@ -0,0 +1,421 @@ +/* Transformer.java -- + Copyright (C) 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.crypto.assembly; + +import gnu.javax.crypto.pad.IPad; + +import java.io.ByteArrayOutputStream; +import java.util.Map; + +/** + * A Transformer is an abstract representation of a two-way + * transformation that can be chained together with other instances of + * this type. Examples of such transformations in this library are: + * {@link Cascade} cipher, {@link gnu.javax.crypto.pad.IPad} algorithm, and a + * ZLib-based deflater/inflater algorithm. A special implementation of a + * Transformer to close a chain is also provided. + *

+ * A Transformer is characterised by the followings: + *

+ *

+ * To allow wiring Transformer instances together, a + * minimal-output-size in bytes is necessary. The trivial case of a + * value of 1 for such attribute practically means that no output + * buffering, from the previous element, is needed --which is independant of + * buffering the input if the Transformer implementation itself + * is block-based. + * + * @see CascadeTransformer + * @see PaddingTransformer + * @see DeflateTransformer + */ +public abstract class Transformer +{ + public static final String DIRECTION = "gnu.crypto.assembly.transformer.direction"; + + protected Direction wired; + + protected Operation mode; + + protected Transformer tail = null; + + protected ByteArrayOutputStream inBuffer = new ByteArrayOutputStream(2048); + + protected ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(2048); + + /** Trivial protected constructor. */ + protected Transformer() + { + super(); + + this.wired = null; + } + + public static final Transformer getCascadeTransformer(Cascade cascade) + { + return new CascadeTransformer(cascade); + } + + public static final Transformer getPaddingTransformer(IPad padding) + { + return new PaddingTransformer(padding); + } + + public static final Transformer getDeflateTransformer() + { + return new DeflateTransformer(); + } + + /** + * Sets the operational mode of this Transformer. + * + * @param mode the processing mode this Transformer is required + * to operate in. + * @throws IllegalStateException if this instance has already been assigned an + * operational mode. + */ + public void setMode(final Operation mode) + { + if (this.mode != null) + throw new IllegalStateException(); + this.mode = mode; + } + + /** + * Returns true if this Transformer was wired in + * pre-processing mode; false otherwise. + * + * @return true if this Transformer has been + * wired in pre-processing mode; false otherwise. + * @throws IllegalStateException if this instance has not yet been assigned an + * operational type. + */ + public boolean isPreProcessing() + { + if (mode == null) + throw new IllegalStateException(); + return (mode == Operation.PRE_PROCESSING); + } + + /** + * Returns true if this Transformer was wired in + * post-processing mode; false otherwise. + * + * @return true if this Transformer has been + * wired in post-processing mode; false otherwise. + * @throws IllegalStateException if this instance has not yet been assigned an + * operational type. + */ + public boolean isPostProcessing() + { + return ! isPreProcessing(); + } + + /** + * Initialises the Transformer for operation with specific + * characteristics. + * + * @param attributes a set of name-value pairs that describes the desired + * future behaviour of this instance. + * @throws IllegalStateException if the instance is already initialised. + */ + public void init(Map attributes) throws TransformerException + { + if (wired != null) + throw new IllegalStateException(); + Direction flow = (Direction) attributes.get(DIRECTION); + if (flow == null) + flow = Direction.FORWARD; + wired = flow; + inBuffer.reset(); + outBuffer.reset(); + tail.init(attributes); // initialise tail first + initDelegate(attributes); // initialise this instance + } + + /** + * Returns the block-size of this Transformer. A value of + * 1 indicates that this instance is block-agnostic. + * + * @return the current minimal required block size. + */ + public int currentBlockSize() + { + if (wired == null) + throw new IllegalStateException(); + return delegateBlockSize(); + } + + /** + * Resets the Transformer for re-initialisation and use with + * other characteristics. This method always succeeds. + */ + public void reset() + { + resetDelegate(); + wired = null; + inBuffer.reset(); + outBuffer.reset(); + tail.reset(); // reset tail last + } + + /** + * Convenience method that calls the method with same name and three + * arguments, using a byte array of length 1 whose contents are + * the designated byte. + * + * @param b the byte to process. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + * @see #update(byte[], int, int) + */ + public byte[] update(byte b) throws TransformerException + { + return update(new byte[] { b }, 0, 1); + } + + /** + * Convenience method that calls the same method with three arguments. All + * bytes in in, starting from index position 0 + * are considered. + * + * @param in the input data bytes. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + * @see #update(byte[], int, int) + */ + public byte[] update(byte[] in) throws TransformerException + { + return update(in, 0, in.length); + } + + /** + * Processes a designated number of bytes from a given byte array. + * + * @param in the input data bytes. + * @param offset index of in from which to start considering + * data. + * @param length the count of bytes to process. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + */ + public byte[] update(byte[] in, int offset, int length) + throws TransformerException + { + if (wired == null) + throw new IllegalStateException(); + byte[] result = (wired == Direction.FORWARD ? forwardUpdate(in, offset, length) + : inverseUpdate(in, offset, length)); + return result; + } + + /** + * Convenience method that calls the same method with three arguments. A + * zero-long byte array is used. + * + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + * @see #lastUpdate(byte[], int, int) + */ + public byte[] lastUpdate() throws TransformerException + { + byte[] result = (wired == Direction.FORWARD ? lastForwardUpdate() + : lastInverseUpdate()); + if (inBuffer.size() != 0) // we still have some buffered bytes + throw new TransformerException("lastUpdate(): input buffer not empty"); + return result; + } + + /** + * Convenience method that calls the method with same name and three + * arguments, using a byte array of length 1 whose contents are + * the designated byte. + * + * @param b the byte to process. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + * @see #lastUpdate(byte[], int, int) + */ + public byte[] lastUpdate(byte b) throws TransformerException + { + return lastUpdate(new byte[] { b }, 0, 1); + } + + /** + * Convenience method that calls the same method with three arguments. All + * bytes in in, starting from index position 0 + * are considered. + * + * @param in the input data bytes. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + * @see #lastUpdate(byte[], int, int) + */ + public byte[] lastUpdate(byte[] in) throws TransformerException + { + return lastUpdate(in, 0, in.length); + } + + /** + * Processes a designated number of bytes from a given byte array and signals, + * at the same time, that this is the last push operation on this + * Transformer. + * + * @param in the input data bytes. + * @param offset index of in from which to start considering + * data. + * @param length the count of bytes to process. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + */ + public byte[] lastUpdate(byte[] in, int offset, int length) + throws TransformerException + { + byte[] result = update(in, offset, length); + byte[] rest = lastUpdate(); + if (rest.length > 0) + { + byte[] newResult = new byte[result.length + rest.length]; + System.arraycopy(result, 0, newResult, 0, result.length); + System.arraycopy(rest, 0, newResult, result.length, rest.length); + result = newResult; + } + return result; + } + + private byte[] forwardUpdate(byte[] in, int off, int len) + throws TransformerException + { + return (isPreProcessing() ? preTransform(in, off, len) + : postTransform(in, off, len)); + } + + private byte[] inverseUpdate(byte[] in, int off, int len) + throws TransformerException + { + return (isPreProcessing() ? postTransform(in, off, len) + : preTransform(in, off, len)); + } + + private byte[] preTransform(byte[] in, int off, int len) + throws TransformerException + { + byte[] result = updateDelegate(in, off, len); + result = tail.update(result); + return result; + } + + private byte[] postTransform(byte[] in, int off, int len) + throws TransformerException + { + byte[] result = tail.update(in, off, len); + result = updateDelegate(result, 0, result.length); + return result; + } + + private byte[] lastForwardUpdate() throws TransformerException + { + return (isPreProcessing() ? preLastTransform() : postLastTransform()); + } + + private byte[] lastInverseUpdate() throws TransformerException + { + return (isPreProcessing() ? postLastTransform() : preLastTransform()); + } + + private byte[] preLastTransform() throws TransformerException + { + byte[] result = lastUpdateDelegate(); + result = tail.lastUpdate(result); + return result; + } + + private byte[] postLastTransform() throws TransformerException + { + byte[] result = tail.lastUpdate(); + result = updateDelegate(result, 0, result.length); + byte[] rest = lastUpdateDelegate(); + if (rest.length > 0) + { + byte[] newResult = new byte[result.length + rest.length]; + System.arraycopy(result, 0, newResult, 0, result.length); + System.arraycopy(rest, 0, newResult, result.length, rest.length); + result = newResult; + } + return result; + } + + abstract void initDelegate(Map attributes) throws TransformerException; + + abstract int delegateBlockSize(); + + abstract void resetDelegate(); + + abstract byte[] updateDelegate(byte[] in, int off, int len) + throws TransformerException; + + abstract byte[] lastUpdateDelegate() throws TransformerException; +} diff --git a/libjava/classpath/gnu/javax/crypto/assembly/TransformerException.java b/libjava/classpath/gnu/javax/crypto/assembly/TransformerException.java new file mode 100644 index 000000000..295fded7b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/TransformerException.java @@ -0,0 +1,140 @@ +/* TransformerException.java -- + Copyright (C) 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.crypto.assembly; + +import gnu.java.lang.CPStringBuilder; + +import java.io.PrintStream; +import java.io.PrintWriter; + +/** + */ +public class TransformerException + extends Exception +{ + private Throwable _exception = null; + + public TransformerException() + { + super(); + } + + public TransformerException(String details) + { + super(details); + } + + public TransformerException(Throwable cause) + { + super(); + + this._exception = cause; + } + + public TransformerException(String details, Throwable cause) + { + super(details); + + this._exception = cause; + } + + public Throwable getCause() + { + return _exception; + } + + /** + * Prints this exception's stack trace to System.err. If this + * exception has a root exception; the stack trace of the root exception is + * also printed to System.err. + */ + public void printStackTrace() + { + super.printStackTrace(); + if (_exception != null) + _exception.printStackTrace(); + } + + /** + * Prints this exception's stack trace to a print stream. If this exception + * has a root exception; the stack trace of the root exception is also printed + * to the print stream. + * + * @param ps the non-null print stream to which to print. + */ + public void printStackTrace(PrintStream ps) + { + super.printStackTrace(ps); + if (_exception != null) + _exception.printStackTrace(ps); + } + + /** + * Prints this exception's stack trace to a print writer. If this exception + * has a root exception; the stack trace of the root exception is also printed + * to the print writer. + * + * @param pw the non-null print writer to use for output. + */ + public void printStackTrace(PrintWriter pw) + { + super.printStackTrace(pw); + if (_exception != null) + _exception.printStackTrace(pw); + } + + /** + * Returns the string representation of this exception. The string + * representation contains this exception's class name, its detailed messsage, + * and if it has a root exception, the string representation of the root + * exception. This string representation is meant for debugging and not meant + * to be interpreted programmatically. + * + * @return the non-null string representation of this exception. + * @see Throwable#getMessage() + */ + public String toString() + { + CPStringBuilder sb = new CPStringBuilder(this.getClass().getName()) + .append(": ").append(super.toString()); + if (_exception != null) + sb.append("; caused by: ").append(_exception.toString()); + return sb.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/Anubis.java b/libjava/classpath/gnu/javax/crypto/cipher/Anubis.java new file mode 100644 index 000000000..3526ad612 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/Anubis.java @@ -0,0 +1,491 @@ +/* Anubis.java -- + 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.crypto.cipher; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.logging.Logger; + +/** + * Anubis is a 128-bit block cipher that accepts a variable-length key. The + * cipher is a uniform substitution-permutation network whose inverse only + * differs from the forward operation in the key schedule. The design of both + * the round transformation and the key schedule is based upon the Wide Trail + * strategy and permits a wide variety of implementation trade-offs. + *

+ * References: + *

    + *
  1. The + * ANUBIS Block Cipher.
    + * Paulo S.L.M. Barreto and Vincent Rijmen.
  2. + *
+ */ +public final class Anubis + extends BaseCipher +{ + private static final Logger log = Logger.getLogger(Anubis.class.getName()); + private static final int DEFAULT_BLOCK_SIZE = 16; // in bytes + private static final int DEFAULT_KEY_SIZE = 16; // in bytes + private static final String Sd = // p. 25 [ANUBIS] + "\uBA54\u2F74\u53D3\uD24D\u50AC\u8DBF\u7052\u9A4C" + + "\uEAD5\u97D1\u3351\u5BA6\uDE48\uA899\uDB32\uB7FC" + + "\uE39E\u919B\uE2BB\u416E\uA5CB\u6B95\uA1F3\uB102" + + "\uCCC4\u1D14\uC363\uDA5D\u5FDC\u7DCD\u7F5A\u6C5C" + + "\uF726\uFFED\uE89D\u6F8E\u19A0\uF089\u0F07\uAFFB" + + "\u0815\u0D04\u0164\uDF76\u79DD\u3D16\u3F37\u6D38" + + "\uB973\uE935\u5571\u7B8C\u7288\uF62A\u3E5E\u2746" + + "\u0C65\u6861\u03C1\u57D6\uD958\uD866\uD73A\uC83C" + + "\uFA96\uA798\uECB8\uC7AE\u694B\uABA9\u670A\u47F2" + + "\uB522\uE5EE\uBE2B\u8112\u831B\u0E23\uF545\u21CE" + + "\u492C\uF9E6\uB628\u1782\u1A8B\uFE8A\u09C9\u874E" + + "\uE12E\uE4E0\uEB90\uA41E\u8560\u0025\uF4F1\u940B" + + "\uE775\uEF34\u31D4\uD086\u7EAD\uFD29\u303B\u9FF8" + + "\uC613\u0605\uC511\u777C\u7A78\u361C\u3959\u1856" + + "\uB3B0\u2420\uB292\uA3C0\u4462\u10B4\u8443\u93C2" + + "\u4ABD\u8F2D\uBC9C\u6A40\uCFA2\u804F\u1FCA\uAA42"; + private static final byte[] S = new byte[256]; + private static final int[] T0 = new int[256]; + private static final int[] T1 = new int[256]; + private static final int[] T2 = new int[256]; + private static final int[] T3 = new int[256]; + private static final int[] T4 = new int[256]; + private static final int[] T5 = new int[256]; + /** + * Anubis round constants. This is the largest possible considering that we + * always use R values, R = 8 + N, and 4 <= N <= 10. + */ + private static final int[] rc = new int[18]; + /** + * KAT vector (from ecb_vk): I=83 + * KEY=000000000000000000002000000000000000000000000000 + * CT=2E66AB15773F3D32FB6C697509460DF4 + */ + private static final byte[] KAT_KEY = + Util.toBytesFromString("000000000000000000002000000000000000000000000000"); + private static final byte[] KAT_CT = + Util.toBytesFromString("2E66AB15773F3D32FB6C697509460DF4"); + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + static + { + long time = System.currentTimeMillis(); + int ROOT = 0x11d; // para. 2.1 [ANUBIS] + int i, s, s2, s4, s6, s8, t; + char c; + for (i = 0; i < 256; i++) + { + c = Sd.charAt(i >>> 1); + s = ((i & 1) == 0 ? c >>> 8 : c) & 0xFF; + S[i] = (byte) s; + s2 = s << 1; + if (s2 > 0xFF) + s2 ^= ROOT; + s4 = s2 << 1; + if (s4 > 0xFF) + s4 ^= ROOT; + s6 = s4 ^ s2; + s8 = s4 << 1; + if (s8 > 0xFF) + s8 ^= ROOT; + T0[i] = s << 24 | s2 << 16 | s4 << 8 | s6; + T1[i] = s2 << 24 | s << 16 | s6 << 8 | s4; + T2[i] = s4 << 24 | s6 << 16 | s << 8 | s2; + T3[i] = s6 << 24 | s4 << 16 | s2 << 8 | s; + T4[i] = s << 24 | s << 16 | s << 8 | s; + T5[s] = s << 24 | s2 << 16 | s6 << 8 | s8; + } + // compute round constant + for (i = 0, s = 0; i < 18;) + rc[i++] = S[(s++) & 0xFF] << 24 + | (S[(s++) & 0xFF] & 0xFF) << 16 + | (S[(s++) & 0xFF] & 0xFF) << 8 + | (S[(s++) & 0xFF] & 0xFF); + time = System.currentTimeMillis() - time; + if (Configuration.DEBUG) + { + log.fine("Static data"); + log.fine("T0[]:"); + StringBuilder sb; + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (t = 0; t < 4; t++) + sb.append("0x").append(Util.toString(T0[i * 4 + t])).append(", "); + log.fine(sb.toString()); + } + log.fine("T1[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (t = 0; t < 4; t++) + sb.append("0x").append(Util.toString(T1[i * 4 + t])).append(", "); + log.fine(sb.toString()); + } + log.fine("T2[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (t = 0; t < 4; t++) + sb.append("0x").append(Util.toString(T2[i * 4 + t])).append(", "); + log.fine(sb.toString()); + } + log.fine("T3[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (t = 0; t < 4; t++) + sb.append("0x").append(Util.toString(T3[i * 4 + t])).append(", "); + log.fine(sb.toString()); + } + log.fine("T4[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (t = 0; t < 4; t++) + sb.append("0x").append(Util.toString(T4[i * 4 + t])).append(", "); + log.fine(sb.toString()); + } + log.fine("T5[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (t = 0; t < 4; t++) + sb.append("0x").append(Util.toString(T5[i * 4 + t])).append(", "); + log.fine(sb.toString()); + } + log.fine("rc[]:"); + for (i = 0; i < 18; i++) + log.fine("0x" + Util.toString(rc[i])); + log.fine("Total initialization time: " + time + " ms."); + } + } + + /** Trivial 0-arguments constructor. */ + public Anubis() + { + super(Registry.ANUBIS_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + private static void anubis(byte[] in, int i, byte[] out, int j, int[][] K) + { + // extract encryption round keys + int R = K.length - 1; + int[] Ker = K[0]; + // mu function + affine key addition + int a0 = (in[i++] << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) ) ^ Ker[0]; + int a1 = (in[i++] << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) ) ^ Ker[1]; + int a2 = (in[i++] << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) ) ^ Ker[2]; + int a3 = (in[i++] << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i] & 0xFF) ) ^ Ker[3]; + int b0, b1, b2, b3; + // round function + for (int r = 1; r < R; r++) + { + Ker = K[r]; + b0 = T0[ a0 >>> 24 ] + ^ T1[ a1 >>> 24 ] + ^ T2[ a2 >>> 24 ] + ^ T3[ a3 >>> 24 ] ^ Ker[0]; + b1 = T0[(a0 >>> 16) & 0xFF] + ^ T1[(a1 >>> 16) & 0xFF] + ^ T2[(a2 >>> 16) & 0xFF] + ^ T3[(a3 >>> 16) & 0xFF] ^ Ker[1]; + b2 = T0[(a0 >>> 8) & 0xFF] + ^ T1[(a1 >>> 8) & 0xFF] + ^ T2[(a2 >>> 8) & 0xFF] + ^ T3[(a3 >>> 8) & 0xFF] ^ Ker[2]; + b3 = T0[ a0 & 0xFF] + ^ T1[ a1 & 0xFF] + ^ T2[ a2 & 0xFF] + ^ T3[ a3 & 0xFF] ^ Ker[3]; + a0 = b0; + a1 = b1; + a2 = b2; + a3 = b3; + if (Configuration.DEBUG) + log.fine("T" + r + "=" + Util.toString(a0) + Util.toString(a1) + + Util.toString(a2) + Util.toString(a3)); + } + // last round function + Ker = K[R]; + int tt = Ker[0]; + out[j++] = (byte)(S[ a0 >>> 24 ] ^ (tt >>> 24)); + out[j++] = (byte)(S[ a1 >>> 24 ] ^ (tt >>> 16)); + out[j++] = (byte)(S[ a2 >>> 24 ] ^ (tt >>> 8)); + out[j++] = (byte)(S[ a3 >>> 24 ] ^ tt); + tt = Ker[1]; + out[j++] = (byte)(S[(a0 >>> 16) & 0xFF] ^ (tt >>> 24)); + out[j++] = (byte)(S[(a1 >>> 16) & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte)(S[(a2 >>> 16) & 0xFF] ^ (tt >>> 8)); + out[j++] = (byte)(S[(a3 >>> 16) & 0xFF] ^ tt); + tt = Ker[2]; + out[j++] = (byte)(S[(a0 >>> 8) & 0xFF] ^ (tt >>> 24)); + out[j++] = (byte)(S[(a1 >>> 8) & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte)(S[(a2 >>> 8) & 0xFF] ^ (tt >>> 8)); + out[j++] = (byte)(S[(a3 >>> 8) & 0xFF] ^ tt); + tt = Ker[3]; + out[j++] = (byte)(S[ a0 & 0xFF] ^ (tt >>> 24)); + out[j++] = (byte)(S[ a1 & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte)(S[ a2 & 0xFF] ^ (tt >>> 8)); + out[j ] = (byte)(S[ a3 & 0xFF] ^ tt); + if (Configuration.DEBUG) + log.fine("T=" + Util.toString(out, j - 15, 16) + "\n"); + } + + public Object clone() + { + Anubis result = new Anubis(); + result.currentBlockSize = this.currentBlockSize; + + return result; + } + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(DEFAULT_BLOCK_SIZE)); + + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + for (int n = 4; n < 10; n++) + al.add(Integer.valueOf(n * 32 / 8)); + return Collections.unmodifiableList(al).iterator(); + } + + /** + * Expands a user-supplied key material into a session key for a designated + * block size. + * + * @param uk the 32N-bit user-supplied key material; 4 <= N <= 10. + * @param bs the desired block size in bytes. + * @return an Object encapsulating the session key. + * @exception IllegalArgumentException if the block size is not 16 (128-bit). + * @exception InvalidKeyException if the key data is invalid. + */ + public Object makeKey(byte[] uk, int bs) throws InvalidKeyException + { + if (bs != DEFAULT_BLOCK_SIZE) + throw new IllegalArgumentException(); + if (uk == null) + throw new InvalidKeyException("Empty key"); + if ((uk.length % 4) != 0) + throw new InvalidKeyException("Key is not multiple of 32-bit."); + int N = uk.length / 4; + if (N < 4 || N > 10) + throw new InvalidKeyException("Key is not 32N; 4 <= N <= 10"); + int R = 8 + N; + int[][] Ke = new int[R + 1][4]; // encryption round keys + int[][] Kd = new int[R + 1][4]; // decryption round keys + int[] tk = new int[N]; + int[] kk = new int[N]; + int r, i, j, k, k0, k1, k2, k3, tt; + // apply mu to k0 + for (r = 0, i = 0; r < N;) + tk[r++] = uk[i++] << 24 + | (uk[i++] & 0xFF) << 16 + | (uk[i++] & 0xFF) << 8 + | (uk[i++] & 0xFF); + for (r = 0; r <= R; r++) + { + if (r > 0) + { + // psi = key evolution function + kk[0] = T0[(tk[0 ] >>> 24) ] + ^ T1[(tk[N - 1] >>> 16) & 0xFF] + ^ T2[(tk[N - 2] >>> 8) & 0xFF] + ^ T3[ tk[N - 3] & 0xFF]; + kk[1] = T0[(tk[1 ] >>> 24) ] + ^ T1[(tk[0 ] >>> 16) & 0xFF] + ^ T2[(tk[N - 1] >>> 8) & 0xFF] + ^ T3[ tk[N - 2] & 0xFF]; + kk[2] = T0[(tk[2 ] >>> 24) ] + ^ T1[(tk[1 ] >>> 16) & 0xFF] + ^ T2[(tk[0 ] >>> 8) & 0xFF] + ^ T3[ tk[N - 1] & 0xFF]; + kk[3] = T0[(tk[3 ] >>> 24) ] + ^ T1[(tk[2 ] >>> 16) & 0xFF] + ^ T2[(tk[1 ] >>> 8) & 0xFF] + ^ T3[ tk[0 ] & 0xFF]; + for (i = 4; i < N; i++) + kk[i] = T0[ tk[i ] >>> 24 ] + ^ T1[(tk[i - 1] >>> 16) & 0xFF] + ^ T2[(tk[i - 2] >>> 8) & 0xFF] + ^ T3[ tk[i - 3] & 0xFF]; + // apply sigma (affine addition) to round constant + tk[0] = rc[r - 1] ^ kk[0]; + for (i = 1; i < N; i++) + tk[i] = kk[i]; + } + // phi = key selection function + tt = tk[N - 1]; + k0 = T4[ tt >>> 24 ]; + k1 = T4[(tt >>> 16) & 0xFF]; + k2 = T4[(tt >>> 8) & 0xFF]; + k3 = T4[ tt & 0xFF]; + for (k = N - 2; k >= 0; k--) + { + tt = tk[k]; + k0 = T4[ tt >>> 24 ] + ^ (T5[(k0 >>> 24) & 0xFF] & 0xFF000000) + ^ (T5[(k0 >>> 16) & 0xFF] & 0x00FF0000) + ^ (T5[(k0 >>> 8) & 0xFF] & 0x0000FF00) + ^ (T5 [k0 & 0xFF] & 0x000000FF); + k1 = T4[(tt >>> 16) & 0xFF] + ^ (T5[(k1 >>> 24) & 0xFF] & 0xFF000000) + ^ (T5[(k1 >>> 16) & 0xFF] & 0x00FF0000) + ^ (T5[(k1 >>> 8) & 0xFF] & 0x0000FF00) + ^ (T5[ k1 & 0xFF] & 0x000000FF); + k2 = T4[(tt >>> 8) & 0xFF] + ^ (T5[(k2 >>> 24) & 0xFF] & 0xFF000000) + ^ (T5[(k2 >>> 16) & 0xFF] & 0x00FF0000) + ^ (T5[(k2 >>> 8) & 0xFF] & 0x0000FF00) + ^ (T5[ k2 & 0xFF] & 0x000000FF); + k3 = T4[ tt & 0xFF] + ^ (T5[(k3 >>> 24) & 0xFF] & 0xFF000000) + ^ (T5[(k3 >>> 16) & 0xFF] & 0x00FF0000) + ^ (T5[(k3 >>> 8) & 0xFF] & 0x0000FF00) + ^ (T5[ k3 & 0xFF] & 0x000000FF); + } + Ke[r][0] = k0; + Ke[r][1] = k1; + Ke[r][2] = k2; + Ke[r][3] = k3; + if (r == 0 || r == R) + { + Kd[R - r][0] = k0; + Kd[R - r][1] = k1; + Kd[R - r][2] = k2; + Kd[R - r][3] = k3; + } + else + { + Kd[R - r][0] = T0[S[ k0 >>> 24 ] & 0xFF] + ^ T1[S[(k0 >>> 16) & 0xFF] & 0xFF] + ^ T2[S[(k0 >>> 8) & 0xFF] & 0xFF] + ^ T3[S[ k0 & 0xFF] & 0xFF]; + Kd[R - r][1] = T0[S[ k1 >>> 24 ] & 0xFF] + ^ T1[S[(k1 >>> 16) & 0xFF] & 0xFF] + ^ T2[S[(k1 >>> 8) & 0xFF] & 0xFF] + ^ T3[S[ k1 & 0xFF] & 0xFF]; + Kd[R - r][2] = T0[S[ k2 >>> 24 ] & 0xFF] + ^ T1[S[(k2 >>> 16) & 0xFF] & 0xFF] + ^ T2[S[(k2 >>> 8) & 0xFF] & 0xFF] + ^ T3[S[ k2 & 0xFF] & 0xFF]; + Kd[R - r][3] = T0[S[ k3 >>> 24 ] & 0xFF] + ^ T1[S[(k3 >>> 16) & 0xFF] & 0xFF] + ^ T2[S[(k3 >>> 8) & 0xFF] & 0xFF] + ^ T3[S[ k3 & 0xFF] & 0xFF]; + } + } + if (Configuration.DEBUG) + { + log.fine("Key schedule"); + log.fine("Ke[]:"); + StringBuilder sb; + for (r = 0; r < R + 1; r++) + { + sb = new StringBuilder("#").append(r).append(": "); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(Ke[r][j])).append(", "); + log.fine(sb.toString()); + } + log.fine("Kd[]:"); + for (r = 0; r < R + 1; r++) + { + sb = new StringBuilder("#").append(r).append(": "); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(Kd[r][j])).append(", "); + log.fine(sb.toString()); + } + } + return new Object[] { Ke, Kd }; + } + + public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + if (bs != DEFAULT_BLOCK_SIZE) + throw new IllegalArgumentException(); + int[][] K = (int[][])((Object[]) k)[0]; + anubis(in, i, out, j, K); + } + + public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + if (bs != DEFAULT_BLOCK_SIZE) + throw new IllegalArgumentException(); + int[][] K = (int[][])((Object[]) k)[1]; + anubis(in, i, out, j, K); + } + + public boolean selfTest() + { + if (valid == null) + { + boolean result = super.selfTest(); // do symmetry tests + if (result) + result = testKat(KAT_KEY, KAT_CT); + valid = Boolean.valueOf(result); + } + return valid.booleanValue(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/BaseCipher.java b/libjava/classpath/gnu/javax/crypto/cipher/BaseCipher.java new file mode 100644 index 000000000..45aa2d6fd --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/BaseCipher.java @@ -0,0 +1,249 @@ +/* BaseCipher.java -- + 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.crypto.cipher; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.Configuration; + +import java.security.InvalidKeyException; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * A basic abstract class to facilitate implementing symmetric key block + * ciphers. + */ +public abstract class BaseCipher + implements IBlockCipher, IBlockCipherSpi +{ + private static final Logger log = Logger.getLogger(BaseCipher.class.getName()); + /** The canonical name prefix of the cipher. */ + protected String name; + /** The default block size, in bytes. */ + protected int defaultBlockSize; + /** The default key size, in bytes. */ + protected int defaultKeySize; + /** The current block size, in bytes. */ + protected int currentBlockSize; + /** The session key for this instance. */ + protected transient Object currentKey; + /** The instance lock. */ + protected Object lock = new Object(); + + /** + * Trivial constructor for use by concrete subclasses. + * + * @param name the canonical name prefix of this instance. + * @param defaultBlockSize the default block size in bytes. + * @param defaultKeySize the default key size in bytes. + */ + protected BaseCipher(String name, int defaultBlockSize, int defaultKeySize) + { + super(); + + this.name = name; + this.defaultBlockSize = defaultBlockSize; + this.defaultKeySize = defaultKeySize; + } + + public abstract Object clone(); + + public String name() + { + CPStringBuilder sb = new CPStringBuilder(name).append('-'); + if (currentKey == null) + sb.append(String.valueOf(8 * defaultBlockSize)); + else + sb.append(String.valueOf(8 * currentBlockSize)); + return sb.toString(); + } + + public int defaultBlockSize() + { + return defaultBlockSize; + } + + public int defaultKeySize() + { + return defaultKeySize; + } + + public void init(Map attributes) throws InvalidKeyException + { + synchronized (lock) + { + if (currentKey != null) + throw new IllegalStateException(); + Integer bs = (Integer) attributes.get(CIPHER_BLOCK_SIZE); + if (bs == null) // no block size was specified + { + if (currentBlockSize == 0) // happy birthday + currentBlockSize = defaultBlockSize; + // else it's a clone. use as is + } + else + { + currentBlockSize = bs.intValue(); + // ensure that value is valid + Iterator it; + boolean ok = false; + for (it = blockSizes(); it.hasNext();) + { + ok = (currentBlockSize == ((Integer) it.next()).intValue()); + if (ok) + break; + } + if (! ok) + throw new IllegalArgumentException(IBlockCipher.CIPHER_BLOCK_SIZE); + } + byte[] k = (byte[]) attributes.get(KEY_MATERIAL); + currentKey = makeKey(k, currentBlockSize); + } + } + + public int currentBlockSize() + { + if (currentKey == null) + throw new IllegalStateException(); + return currentBlockSize; + } + + public void reset() + { + synchronized (lock) + { + currentKey = null; + } + } + + public void encryptBlock(byte[] in, int inOffset, byte[] out, int outOffset) + throws IllegalStateException + { + synchronized (lock) + { + if (currentKey == null) + throw new IllegalStateException(); + encrypt(in, inOffset, out, outOffset, currentKey, currentBlockSize); + } + } + + public void decryptBlock(byte[] in, int inOffset, byte[] out, int outOffset) + throws IllegalStateException + { + synchronized (lock) + { + if (currentKey == null) + throw new IllegalStateException(); + decrypt(in, inOffset, out, outOffset, currentKey, currentBlockSize); + } + } + + public boolean selfTest() + { + int ks; + Iterator bit; + // do symmetry tests for all block-size/key-size combos + for (Iterator kit = keySizes(); kit.hasNext();) + { + ks = ((Integer) kit.next()).intValue(); + for (bit = blockSizes(); bit.hasNext();) + if (! testSymmetry(ks, ((Integer) bit.next()).intValue())) + return false; + } + return true; + } + + private boolean testSymmetry(int ks, int bs) + { + try + { + byte[] kb = new byte[ks]; + byte[] pt = new byte[bs]; + byte[] ct = new byte[bs]; + byte[] cpt = new byte[bs]; + int i; + for (i = 0; i < ks; i++) + kb[i] = (byte) i; + for (i = 0; i < bs; i++) + pt[i] = (byte) i; + Object k = makeKey(kb, bs); + encrypt(pt, 0, ct, 0, k, bs); + decrypt(ct, 0, cpt, 0, k, bs); + return Arrays.equals(pt, cpt); + } + catch (Exception x) + { + if (Configuration.DEBUG) + log.log(Level.FINE, "Exception in testSymmetry() for " + name(), x); + return false; + } + } + + protected boolean testKat(byte[] kb, byte[] ct) + { + return testKat(kb, ct, new byte[ct.length]); // all-zero plaintext + } + + protected boolean testKat(byte[] kb, byte[] ct, byte[] pt) + { + try + { + int bs = pt.length; + byte[] t = new byte[bs]; + Object k = makeKey(kb, bs); + // test encryption + encrypt(pt, 0, t, 0, k, bs); + if (! Arrays.equals(t, ct)) + return false; + // test decryption + decrypt(t, 0, t, 0, k, bs); + return Arrays.equals(t, pt); + } + catch (Exception x) + { + if (Configuration.DEBUG) + log.log(Level.FINE, "Exception in testKat() for " + name(), x); + return false; + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/Blowfish.java b/libjava/classpath/gnu/javax/crypto/cipher/Blowfish.java new file mode 100644 index 000000000..0c6d9b12b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/Blowfish.java @@ -0,0 +1,611 @@ +/* Blowfish.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +// -------------------------------------------------------------------------- +// +// Based on the C implementation from the GNU Privacy Guard. +// +// -------------------------------------------------------------------------- + +package gnu.javax.crypto.cipher; + +import gnu.java.security.Registry; +import gnu.java.security.util.Sequence; +import gnu.java.security.util.Util; + +import java.util.Collections; +import java.util.Iterator; + +/** + * Blowfish is a 16-round, 64-bit Feistel cipher designed by Bruce Schneier. It + * accepts a variable-length key of up to 448 bits. + *

+ * References: + *

    + *
  1. Schneier, Bruce: Applied Cryptography, Second Edition, 336--339, + * 647--654 (1996 Bruce Schneier).
  2. + *
  3. The Blowfish + * Encryption Algorithm.
  4. + *
+ */ +public class Blowfish + extends BaseCipher +{ + private static final int DEFAULT_BLOCK_SIZE = 8; + private static final int DEFAULT_KEY_SIZE = 8; + private static final int MAX_KEY_LENGTH = 56; + /** Initial value of the p-array. */ + private static final int[] P = { + 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, + 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, + 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b }; + /** Initial value of S-box 1. */ + static final int[] KS0 = { + 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, + 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, + 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658, + 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, + 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, + 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, + 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6, + 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, + 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, + 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, + 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1, + 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, + 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, + 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, + 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176, + 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, + 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, + 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, + 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b, + 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, + 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, + 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, + 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a, + 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, + 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, + 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, + 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8, + 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, + 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, + 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, + 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0, + 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, + 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, + 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, + 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705, + 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, + 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, + 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, + 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9, + 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, + 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, + 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, + 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a }; + /** Initial value of S-box 2. */ + private static final int[] KS1 = { + 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, + 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, + 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65, + 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, + 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, + 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, + 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d, + 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, + 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, + 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, + 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908, + 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, + 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, + 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, + 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908, + 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, + 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, + 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, + 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa, + 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, + 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, + 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, + 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5, + 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, + 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, + 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, + 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca, + 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, + 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, + 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, + 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054, + 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, + 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, + 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, + 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646, + 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, + 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, + 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, + 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e, + 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, + 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, + 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, + 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7 }; + /** Initial value of S-box 3. */ + private static final int[] KS2 = { + 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, + 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, + 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af, + 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, + 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, + 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, + 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec, + 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, + 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, + 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, + 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58, + 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, + 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, + 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, + 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60, + 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, + 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, + 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, + 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74, + 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, + 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, + 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, + 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979, + 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, + 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, + 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, + 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086, + 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, + 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, + 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, + 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84, + 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, + 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, + 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, + 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe, + 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, + 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, + 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, + 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188, + 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, + 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, + 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, + 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0 }; + /** Initial value of S-box 4. */ + private static final int[] KS3 = { + 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, + 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, + 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79, + 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, + 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, + 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, + 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1, + 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, + 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, + 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, + 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6, + 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, + 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, + 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, + 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5, + 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, + 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, + 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, + 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd, + 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, + 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, + 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, + 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc, + 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, + 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, + 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, + 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a, + 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, + 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, + 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, + 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b, + 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, + 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, + 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, + 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623, + 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, + 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, + 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, + 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3, + 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, + 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, + 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, + 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 }; + /** Cache of the self test. */ + private static Boolean valid; + /** + * Test vector, as published in + * href="http://www.counterpane.com/vectors.txt">http://www.counterpane.com/vectors.txt. + * + * KEY=0000000000000000 + * PT=0000000000000000 + * CT=4EF997456198DD78 + */ + private static final byte[] TV_KEY = Util.toBytesFromString("0000000000000000"); + private static final byte[] TV_CT = Util.toBytesFromString("4EF997456198DD78"); + + public Blowfish() + { + super(Registry.BLOWFISH_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + public Object clone() + { + Blowfish result = new Blowfish(); + result.currentBlockSize = currentBlockSize; + return result; + } + + public Iterator keySizes() + { + return new Sequence(8, MAX_KEY_LENGTH, 8).iterator(); + } + + public Iterator blockSizes() + { + return Collections.singleton(Integer.valueOf(DEFAULT_BLOCK_SIZE)).iterator(); + } + + public Object makeKey(byte[] k, int bs) + { + Context ctx = new Context(); + System.arraycopy(P, 0, ctx.p, 0, P.length); + System.arraycopy(KS0, 0, ctx.s0, 0, KS0.length); + System.arraycopy(KS1, 0, ctx.s1, 0, KS1.length); + System.arraycopy(KS2, 0, ctx.s2, 0, KS2.length); + System.arraycopy(KS3, 0, ctx.s3, 0, KS3.length); + // XOR the key with the P-box + int l = 0; + for (int i = 0; i < ctx.p.length; i++) + { + int data = 0; + for (int j = 0; j < 4; j++) + { + data = (data << 8) | (k[l++] & 0xff); + if (l >= k.length) + l = 0; + } + ctx.p[i] ^= data; + } + // We swap the left and right words here only, so we can avoid + // swapping altogether during encryption/decryption. + int t; + Block x = new Block(); + x.left = x.right = 0; + for (int i = 0; i < ctx.p.length; i += 2) + { + blowfishEncrypt(x, ctx); + ctx.p[i] = x.right; + ctx.p[i + 1] = x.left; + t = x.right; + x.right = x.left; + x.left = t; + } + for (int i = 0; i < ctx.s0.length; i += 2) + { + blowfishEncrypt(x, ctx); + ctx.s0[i] = x.right; + ctx.s0[i + 1] = x.left; + t = x.right; + x.right = x.left; + x.left = t; + } + for (int i = 0; i < ctx.s1.length; i += 2) + { + blowfishEncrypt(x, ctx); + ctx.s1[i] = x.right; + ctx.s1[i + 1] = x.left; + t = x.right; + x.right = x.left; + x.left = t; + } + for (int i = 0; i < ctx.s2.length; i += 2) + { + blowfishEncrypt(x, ctx); + ctx.s2[i] = x.right; + ctx.s2[i + 1] = x.left; + t = x.right; + x.right = x.left; + x.left = t; + } + for (int i = 0; i < ctx.s3.length; i += 2) + { + blowfishEncrypt(x, ctx); + ctx.s3[i] = x.right; + ctx.s3[i + 1] = x.left; + t = x.right; + x.right = x.left; + x.left = t; + } + x.left = x.right = 0; + return ctx; + } + + public void encrypt(byte[] in, int i, byte[] out, int o, Object k, int bs) + { + Block x = new Block(); + x.left = (in[i ] & 0xff) << 24 + | (in[i + 1] & 0xff) << 16 + | (in[i + 2] & 0xff) << 8 + | (in[i + 3] & 0xff); + x.right = (in[i + 4] & 0xff) << 24 + | (in[i + 5] & 0xff) << 16 + | (in[i + 6] & 0xff) << 8 + | (in[i + 7] & 0xff); + blowfishEncrypt(x, (Context) k); + out[o ] = (byte)(x.right >>> 24); + out[o + 1] = (byte)(x.right >>> 16); + out[o + 2] = (byte)(x.right >>> 8); + out[o + 3] = (byte) x.right; + out[o + 4] = (byte)(x.left >>> 24); + out[o + 5] = (byte)(x.left >>> 16); + out[o + 6] = (byte)(x.left >>> 8); + out[o + 7] = (byte) x.left; + x.left = x.right = 0; + } + + public void decrypt(byte[] in, int i, byte[] out, int o, Object k, int bs) + { + Block x = new Block(); + x.left = (in[i ] & 0xff) << 24 + | (in[i + 1] & 0xff) << 16 + | (in[i + 2] & 0xff) << 8 + | (in[i + 3] & 0xff); + x.right = (in[i + 4] & 0xff) << 24 + | (in[i + 5] & 0xff) << 16 + | (in[i + 6] & 0xff) << 8 + | (in[i + 7] & 0xff); + blowfishDecrypt(x, (Context) k); + out[o ] = (byte)(x.right >>> 24); + out[o + 1] = (byte)(x.right >>> 16); + out[o + 2] = (byte)(x.right >>> 8); + out[o + 3] = (byte) x.right; + out[o + 4] = (byte)(x.left >>> 24); + out[o + 5] = (byte)(x.left >>> 16); + out[o + 6] = (byte)(x.left >>> 8); + out[o + 7] = (byte) x.left; + x.left = x.right = 0; + } + + /** Encrypt a single pair of 32-bit integers. */ + private void blowfishEncrypt(Block x, Context ctx) + { + int[] p = ctx.p; + int[] s0 = ctx.s0, s1 = ctx.s1, s2 = ctx.s2, s3 = ctx.s3; + x.left ^= p[0]; + x.right ^= ((s0[x.left >>> 24 ] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[1]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[2]; + x.right ^= ((s0[x.left >>> 24 ] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[3]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[4]; + x.right ^= ((s0[x.left >>> 24 ] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[5]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[6]; + x.right ^= ((s0[x.left >>> 24 ] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[7]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[8]; + x.right ^= ((s0[x.left >>> 24 ] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[9]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[10]; + x.right ^= ((s0[x.left >>> 24 ] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[11]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[12]; + x.right ^= ((s0[x.left >>> 24 ] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[13]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[14]; + x.right ^= ((s0[x.left >>> 24 ] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[15]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[16]; + x.right ^= p[17]; + } + + /** Decrypt a single pair of 32-bit integers. */ + private void blowfishDecrypt(Block x, Context ctx) + { + int[] p = ctx.p; + int[] s0 = ctx.s0, s1 = ctx.s1, s2 = ctx.s2, s3 = ctx.s3; + x.left ^= p[17]; + x.right ^= ((s0[x.left >>> 24 ] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[16]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[15]; + x.right ^= ((s0[x.left >>> 24 ] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[14]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[13]; + x.right ^= ((s0[x.left >>> 24 ] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[12]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[11]; + x.right ^= ((s0[x.left >>> 24 ] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[10]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[9]; + x.right ^= ((s0[x.left >>> 24] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[8]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[7]; + x.right ^= ((s0[x.left >>> 24 ] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[6]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[5]; + x.right ^= ((s0[x.left >>> 24 ] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[4]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[3]; + x.right ^= ((s0[x.left >>> 24 ] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[2]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[1]; + x.right ^= p[0]; + } + + public boolean selfTest() + { + if (valid == null) + { + boolean result = super.selfTest(); // symmetry + if (result) + result = testKat(TV_KEY, TV_CT); + valid = Boolean.valueOf(result); + } + return valid.booleanValue(); + } + + /** A simple wrapper for the P- and S-boxes. */ + private class Context + implements Cloneable + { + /** The P-array. */ + int[] p, s0, s1, s2, s3; + + /** Default 0-arguments constructor. */ + Context() + { + p = new int[18]; + s0 = new int[256]; + s1 = new int[256]; + s2 = new int[256]; + s3 = new int[256]; + } + + /** + * Private constructor for cloneing. + * + * @param that The instance being cloned. + */ + private Context(Context that) + { + this.p = (int[]) that.p.clone(); + this.s0 = (int[]) that.s0.clone(); + this.s1 = (int[]) that.s1.clone(); + this.s2 = (int[]) that.s2.clone(); + this.s3 = (int[]) that.s3.clone(); + } + + public Object clone() + { + return new Context(this); + } + } + + private class Block + { + int left, right; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/Cast5.java b/libjava/classpath/gnu/javax/crypto/cipher/Cast5.java new file mode 100644 index 000000000..47b29226f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/Cast5.java @@ -0,0 +1,987 @@ +/* Cast5.java -- + Copyright (C) 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.crypto.cipher; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; + +/** + * An implmenetation of the CAST5 (a.k.a. CAST-128) algorithm, + * as per RFC-2144, dated May 1997. + *

+ * In this RFC, Carlisle Adams (the CA in CAST, ST stands for + * Stafford Tavares) describes CAST5 as: + *

+ * "...a DES-like Substitution-Permutation Network (SPN) cryptosystem which + * appears to have good resistance to differential cryptanalysis, linear + * cryptanalysis, and related-key cryptanalysis. This cipher also possesses + * a number of other desirable cryptographic properties, including avalanche, + * Strict Avalanche Criterion (SAC), Bit Independence Criterion (BIC), no + * complementation property, and an absence of weak and semi-weak keys." + *
+ *

+ * CAST5 is a symmetric block cipher with a block-size of 8 + * bytes and a variable key-size of up to 128 bits. Its authors, and their + * employer (Entrust Technologies, a Nortel majority-owned company), made it + * available worldwide on a royalty-free basis for commercial and non-commercial + * uses. + *

+ * The CAST5 encryption algorithm has been designed to allow a + * key size that can vary from 40 bits to 128 bits, + * in 8-bit increments (that is, the allowable key sizes are 40, 48, 56, + * 64, ..., 112, 120, and 128 bits. For variable keysize + * operation, the specification is as follows: + *

    + *
  1. For key sizes up to and including 80 bits (i.e., + * 40, 48, 56, 64, 72, and 80 bits), the algorithm + * is exactly as specified but uses 12 rounds instead of + * 16;
  2. + *
  3. For key sizes greater than 80 bits, the algorithm uses + * the full 16 rounds;
  4. + *
  5. For key sizes less than 128 bits, the key is padded with + * zero bytes (in the rightmost, or least significant, positions) out to + * 128 bits (since the CAST5 key schedule assumes + * an input key of 128 bits).
  6. + *
+ *

+ * References: + *

    + *
  1. The CAST-128 Encryption + * Algorithm.
    + * Carlisle Adams.
  2. + *
+ */ +public class Cast5 + extends BaseCipher +{ + private static final int DEFAULT_BLOCK_SIZE = 8; // in bytes + private static final int DEFAULT_KEY_SIZE = 5; // in bytes + /** + * KAT vector (from rfc-2144): + * 40-bit key = 01 23 45 67 12 + * = 01 23 45 67 12 00 00 00 00 00 00 00 00 00 00 00 + * plaintext = 01 23 45 67 89 AB CD EF + * ciphertext = 7A C8 16 D1 6E 9B 30 2E + */ + private static final byte[] KAT_KEY = Util.toBytesFromString("0123456712"); + private static final byte[] KAT_PT = Util.toBytesFromString("0123456789ABCDEF"); + private static final byte[] KAT_CT = Util.toBytesFromString("7AC816D16E9B302E"); + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + // CAST5 S-boxes + private static final int[] S1 = { + 0x30FB40D4, 0x9FA0FF0B, 0x6BECCD2F, 0x3F258C7A, 0x1E213F2F, 0x9C004DD3, + 0x6003E540, 0xCF9FC949, 0xBFD4AF27, 0x88BBBDB5, 0xE2034090, 0x98D09675, + 0x6E63A0E0, 0x15C361D2, 0xC2E7661D, 0x22D4FF8E, 0x28683B6F, 0xC07FD059, + 0xFF2379C8, 0x775F50E2, 0x43C340D3, 0xDF2F8656, 0x887CA41A, 0xA2D2BD2D, + 0xA1C9E0D6, 0x346C4819, 0x61B76D87, 0x22540F2F, 0x2ABE32E1, 0xAA54166B, + 0x22568E3A, 0xA2D341D0, 0x66DB40C8, 0xA784392F, 0x004DFF2F, 0x2DB9D2DE, + 0x97943FAC, 0x4A97C1D8, 0x527644B7, 0xB5F437A7, 0xB82CBAEF, 0xD751D159, + 0x6FF7F0ED, 0x5A097A1F, 0x827B68D0, 0x90ECF52E, 0x22B0C054, 0xBC8E5935, + 0x4B6D2F7F, 0x50BB64A2, 0xD2664910, 0xBEE5812D, 0xB7332290, 0xE93B159F, + 0xB48EE411, 0x4BFF345D, 0xFD45C240, 0xAD31973F, 0xC4F6D02E, 0x55FC8165, + 0xD5B1CAAD, 0xA1AC2DAE, 0xA2D4B76D, 0xC19B0C50, 0x882240F2, 0x0C6E4F38, + 0xA4E4BFD7, 0x4F5BA272, 0x564C1D2F, 0xC59C5319, 0xB949E354, 0xB04669FE, + 0xB1B6AB8A, 0xC71358DD, 0x6385C545, 0x110F935D, 0x57538AD5, 0x6A390493, + 0xE63D37E0, 0x2A54F6B3, 0x3A787D5F, 0x6276A0B5, 0x19A6FCDF, 0x7A42206A, + 0x29F9D4D5, 0xF61B1891, 0xBB72275E, 0xAA508167, 0x38901091, 0xC6B505EB, + 0x84C7CB8C, 0x2AD75A0F, 0x874A1427, 0xA2D1936B, 0x2AD286AF, 0xAA56D291, + 0xD7894360, 0x425C750D, 0x93B39E26, 0x187184C9, 0x6C00B32D, 0x73E2BB14, + 0xA0BEBC3C, 0x54623779, 0x64459EAB, 0x3F328B82, 0x7718CF82, 0x59A2CEA6, + 0x04EE002E, 0x89FE78E6, 0x3FAB0950, 0x325FF6C2, 0x81383F05, 0x6963C5C8, + 0x76CB5AD6, 0xD49974C9, 0xCA180DCF, 0x380782D5, 0xC7FA5CF6, 0x8AC31511, + 0x35E79E13, 0x47DA91D0, 0xF40F9086, 0xA7E2419E, 0x31366241, 0x051EF495, + 0xAA573B04, 0x4A805D8D, 0x548300D0, 0x00322A3C, 0xBF64CDDF, 0xBA57A68E, + 0x75C6372B, 0x50AFD341, 0xA7C13275, 0x915A0BF5, 0x6B54BFAB, 0x2B0B1426, + 0xAB4CC9D7, 0x449CCD82, 0xF7FBF265, 0xAB85C5F3, 0x1B55DB94, 0xAAD4E324, + 0xCFA4BD3F, 0x2DEAA3E2, 0x9E204D02, 0xC8BD25AC, 0xEADF55B3, 0xD5BD9E98, + 0xE31231B2, 0x2AD5AD6C, 0x954329DE, 0xADBE4528, 0xD8710F69, 0xAA51C90F, + 0xAA786BF6, 0x22513F1E, 0xAA51A79B, 0x2AD344CC, 0x7B5A41F0, 0xD37CFBAD, + 0x1B069505, 0x41ECE491, 0xB4C332E6, 0x032268D4, 0xC9600ACC, 0xCE387E6D, + 0xBF6BB16C, 0x6A70FB78, 0x0D03D9C9, 0xD4DF39DE, 0xE01063DA, 0x4736F464, + 0x5AD328D8, 0xB347CC96, 0x75BB0FC3, 0x98511BFB, 0x4FFBCC35, 0xB58BCF6A, + 0xE11F0ABC, 0xBFC5FE4A, 0xA70AEC10, 0xAC39570A, 0x3F04442F, 0x6188B153, + 0xE0397A2E, 0x5727CB79, 0x9CEB418F, 0x1CACD68D, 0x2AD37C96, 0x0175CB9D, + 0xC69DFF09, 0xC75B65F0, 0xD9DB40D8, 0xEC0E7779, 0x4744EAD4, 0xB11C3274, + 0xDD24CB9E, 0x7E1C54BD, 0xF01144F9, 0xD2240EB1, 0x9675B3FD, 0xA3AC3755, + 0xD47C27AF, 0x51C85F4D, 0x56907596, 0xA5BB15E6, 0x580304F0, 0xCA042CF1, + 0x011A37EA, 0x8DBFAADB, 0x35BA3E4A, 0x3526FFA0, 0xC37B4D09, 0xBC306ED9, + 0x98A52666, 0x5648F725, 0xFF5E569D, 0x0CED63D0, 0x7C63B2CF, 0x700B45E1, + 0xD5EA50F1, 0x85A92872, 0xAF1FBDA7, 0xD4234870, 0xA7870BF3, 0x2D3B4D79, + 0x42E04198, 0x0CD0EDE7, 0x26470DB8, 0xF881814C, 0x474D6AD7, 0x7C0C5E5C, + 0xD1231959, 0x381B7298, 0xF5D2F4DB, 0xAB838653, 0x6E2F1E23, 0x83719C9E, + 0xBD91E046, 0x9A56456E, 0xDC39200C, 0x20C8C571, 0x962BDA1C, 0xE1E696FF, + 0xB141AB08, 0x7CCA89B9, 0x1A69E783, 0x02CC4843, 0xA2F7C579, 0x429EF47D, + 0x427B169C, 0x5AC9F049, 0xDD8F0F00, 0x5C8165BF }; + private static final int[] S2 = { + 0x1F201094, 0xEF0BA75B, 0x69E3CF7E, 0x393F4380, 0xFE61CF7A, 0xEEC5207A, + 0x55889C94, 0x72FC0651, 0xADA7EF79, 0x4E1D7235, 0xD55A63CE, 0xDE0436BA, + 0x99C430EF, 0x5F0C0794, 0x18DCDB7D, 0xA1D6EFF3, 0xA0B52F7B, 0x59E83605, + 0xEE15B094, 0xE9FFD909, 0xDC440086, 0xEF944459, 0xBA83CCB3, 0xE0C3CDFB, + 0xD1DA4181, 0x3B092AB1, 0xF997F1C1, 0xA5E6CF7B, 0x01420DDB, 0xE4E7EF5B, + 0x25A1FF41, 0xE180F806, 0x1FC41080, 0x179BEE7A, 0xD37AC6A9, 0xFE5830A4, + 0x98DE8B7F, 0x77E83F4E, 0x79929269, 0x24FA9F7B, 0xE113C85B, 0xACC40083, + 0xD7503525, 0xF7EA615F, 0x62143154, 0x0D554B63, 0x5D681121, 0xC866C359, + 0x3D63CF73, 0xCEE234C0, 0xD4D87E87, 0x5C672B21, 0x071F6181, 0x39F7627F, + 0x361E3084, 0xE4EB573B, 0x602F64A4, 0xD63ACD9C, 0x1BBC4635, 0x9E81032D, + 0x2701F50C, 0x99847AB4, 0xA0E3DF79, 0xBA6CF38C, 0x10843094, 0x2537A95E, + 0xF46F6FFE, 0xA1FF3B1F, 0x208CFB6A, 0x8F458C74, 0xD9E0A227, 0x4EC73A34, + 0xFC884F69, 0x3E4DE8DF, 0xEF0E0088, 0x3559648D, 0x8A45388C, 0x1D804366, + 0x721D9BFD, 0xA58684BB, 0xE8256333, 0x844E8212, 0x128D8098, 0xFED33FB4, + 0xCE280AE1, 0x27E19BA5, 0xD5A6C252, 0xE49754BD, 0xC5D655DD, 0xEB667064, + 0x77840B4D, 0xA1B6A801, 0x84DB26A9, 0xE0B56714, 0x21F043B7, 0xE5D05860, + 0x54F03084, 0x066FF472, 0xA31AA153, 0xDADC4755, 0xB5625DBF, 0x68561BE6, + 0x83CA6B94, 0x2D6ED23B, 0xECCF01DB, 0xA6D3D0BA, 0xB6803D5C, 0xAF77A709, + 0x33B4A34C, 0x397BC8D6, 0x5EE22B95, 0x5F0E5304, 0x81ED6F61, 0x20E74364, + 0xB45E1378, 0xDE18639B, 0x881CA122, 0xB96726D1, 0x8049A7E8, 0x22B7DA7B, + 0x5E552D25, 0x5272D237, 0x79D2951C, 0xC60D894C, 0x488CB402, 0x1BA4FE5B, + 0xA4B09F6B, 0x1CA815CF, 0xA20C3005, 0x8871DF63, 0xB9DE2FCB, 0x0CC6C9E9, + 0x0BEEFF53, 0xE3214517, 0xB4542835, 0x9F63293C, 0xEE41E729, 0x6E1D2D7C, + 0x50045286, 0x1E6685F3, 0xF33401C6, 0x30A22C95, 0x31A70850, 0x60930F13, + 0x73F98417, 0xA1269859, 0xEC645C44, 0x52C877A9, 0xCDFF33A6, 0xA02B1741, + 0x7CBAD9A2, 0x2180036F, 0x50D99C08, 0xCB3F4861, 0xC26BD765, 0x64A3F6AB, + 0x80342676, 0x25A75E7B, 0xE4E6D1FC, 0x20C710E6, 0xCDF0B680, 0x17844D3B, + 0x31EEF84D, 0x7E0824E4, 0x2CCB49EB, 0x846A3BAE, 0x8FF77888, 0xEE5D60F6, + 0x7AF75673, 0x2FDD5CDB, 0xA11631C1, 0x30F66F43, 0xB3FAEC54, 0x157FD7FA, + 0xEF8579CC, 0xD152DE58, 0xDB2FFD5E, 0x8F32CE19, 0x306AF97A, 0x02F03EF8, + 0x99319AD5, 0xC242FA0F, 0xA7E3EBB0, 0xC68E4906, 0xB8DA230C, 0x80823028, + 0xDCDEF3C8, 0xD35FB171, 0x088A1BC8, 0xBEC0C560, 0x61A3C9E8, 0xBCA8F54D, + 0xC72FEFFA, 0x22822E99, 0x82C570B4, 0xD8D94E89, 0x8B1C34BC, 0x301E16E6, + 0x273BE979, 0xB0FFEAA6, 0x61D9B8C6, 0x00B24869, 0xB7FFCE3F, 0x08DC283B, + 0x43DAF65A, 0xF7E19798, 0x7619B72F, 0x8F1C9BA4, 0xDC8637A0, 0x16A7D3B1, + 0x9FC393B7, 0xA7136EEB, 0xC6BCC63E, 0x1A513742, 0xEF6828BC, 0x520365D6, + 0x2D6A77AB, 0x3527ED4B, 0x821FD216, 0x095C6E2E, 0xDB92F2FB, 0x5EEA29CB, + 0x145892F5, 0x91584F7F, 0x5483697B, 0x2667A8CC, 0x85196048, 0x8C4BACEA, + 0x833860D4, 0x0D23E0F9, 0x6C387E8A, 0x0AE6D249, 0xB284600C, 0xD835731D, + 0xDCB1C647, 0xAC4C56EA, 0x3EBD81B3, 0x230EABB0, 0x6438BC87, 0xF0B5B1FA, + 0x8F5EA2B3, 0xFC184642, 0x0A036B7A, 0x4FB089BD, 0x649DA589, 0xA345415E, + 0x5C038323, 0x3E5D3BB9, 0x43D79572, 0x7E6DD07C, 0x06DFDF1E, 0x6C6CC4EF, + 0x7160A539, 0x73BFBE70, 0x83877605, 0x4523ECF1 }; + private static final int[] S3 = { + 0x8DEFC240, 0x25FA5D9F, 0xEB903DBF, 0xE810C907, 0x47607FFF, 0x369FE44B, + 0x8C1FC644, 0xAECECA90, 0xBEB1F9BF, 0xEEFBCAEA, 0xE8CF1950, 0x51DF07AE, + 0x920E8806, 0xF0AD0548, 0xE13C8D83, 0x927010D5, 0x11107D9F, 0x07647DB9, + 0xB2E3E4D4, 0x3D4F285E, 0xB9AFA820, 0xFADE82E0, 0xA067268B, 0x8272792E, + 0x553FB2C0, 0x489AE22B, 0xD4EF9794, 0x125E3FBC, 0x21FFFCEE, 0x825B1BFD, + 0x9255C5ED, 0x1257A240, 0x4E1A8302, 0xBAE07FFF, 0x528246E7, 0x8E57140E, + 0x3373F7BF, 0x8C9F8188, 0xA6FC4EE8, 0xC982B5A5, 0xA8C01DB7, 0x579FC264, + 0x67094F31, 0xF2BD3F5F, 0x40FFF7C1, 0x1FB78DFC, 0x8E6BD2C1, 0x437BE59B, + 0x99B03DBF, 0xB5DBC64B, 0x638DC0E6, 0x55819D99, 0xA197C81C, 0x4A012D6E, + 0xC5884A28, 0xCCC36F71, 0xB843C213, 0x6C0743F1, 0x8309893C, 0x0FEDDD5F, + 0x2F7FE850, 0xD7C07F7E, 0x02507FBF, 0x5AFB9A04, 0xA747D2D0, 0x1651192E, + 0xAF70BF3E, 0x58C31380, 0x5F98302E, 0x727CC3C4, 0x0A0FB402, 0x0F7FEF82, + 0x8C96FDAD, 0x5D2C2AAE, 0x8EE99A49, 0x50DA88B8, 0x8427F4A0, 0x1EAC5790, + 0x796FB449, 0x8252DC15, 0xEFBD7D9B, 0xA672597D, 0xADA840D8, 0x45F54504, + 0xFA5D7403, 0xE83EC305, 0x4F91751A, 0x925669C2, 0x23EFE941, 0xA903F12E, + 0x60270DF2, 0x0276E4B6, 0x94FD6574, 0x927985B2, 0x8276DBCB, 0x02778176, + 0xF8AF918D, 0x4E48F79E, 0x8F616DDF, 0xE29D840E, 0x842F7D83, 0x340CE5C8, + 0x96BBB682, 0x93B4B148, 0xEF303CAB, 0x984FAF28, 0x779FAF9B, 0x92DC560D, + 0x224D1E20, 0x8437AA88, 0x7D29DC96, 0x2756D3DC, 0x8B907CEE, 0xB51FD240, + 0xE7C07CE3, 0xE566B4A1, 0xC3E9615E, 0x3CF8209D, 0x6094D1E3, 0xCD9CA341, + 0x5C76460E, 0x00EA983B, 0xD4D67881, 0xFD47572C, 0xF76CEDD9, 0xBDA8229C, + 0x127DADAA, 0x438A074E, 0x1F97C090, 0x081BDB8A, 0x93A07EBE, 0xB938CA15, + 0x97B03CFF, 0x3DC2C0F8, 0x8D1AB2EC, 0x64380E51, 0x68CC7BFB, 0xD90F2788, + 0x12490181, 0x5DE5FFD4, 0xDD7EF86A, 0x76A2E214, 0xB9A40368, 0x925D958F, + 0x4B39FFFA, 0xBA39AEE9, 0xA4FFD30B, 0xFAF7933B, 0x6D498623, 0x193CBCFA, + 0x27627545, 0x825CF47A, 0x61BD8BA0, 0xD11E42D1, 0xCEAD04F4, 0x127EA392, + 0x10428DB7, 0x8272A972, 0x9270C4A8, 0x127DE50B, 0x285BA1C8, 0x3C62F44F, + 0x35C0EAA5, 0xE805D231, 0x428929FB, 0xB4FCDF82, 0x4FB66A53, 0x0E7DC15B, + 0x1F081FAB, 0x108618AE, 0xFCFD086D, 0xF9FF2889, 0x694BCC11, 0x236A5CAE, + 0x12DECA4D, 0x2C3F8CC5, 0xD2D02DFE, 0xF8EF5896, 0xE4CF52DA, 0x95155B67, + 0x494A488C, 0xB9B6A80C, 0x5C8F82BC, 0x89D36B45, 0x3A609437, 0xEC00C9A9, + 0x44715253, 0x0A874B49, 0xD773BC40, 0x7C34671C, 0x02717EF6, 0x4FEB5536, + 0xA2D02FFF, 0xD2BF60C4, 0xD43F03C0, 0x50B4EF6D, 0x07478CD1, 0x006E1888, + 0xA2E53F55, 0xB9E6D4BC, 0xA2048016, 0x97573833, 0xD7207D67, 0xDE0F8F3D, + 0x72F87B33, 0xABCC4F33, 0x7688C55D, 0x7B00A6B0, 0x947B0001, 0x570075D2, + 0xF9BB88F8, 0x8942019E, 0x4264A5FF, 0x856302E0, 0x72DBD92B, 0xEE971B69, + 0x6EA22FDE, 0x5F08AE2B, 0xAF7A616D, 0xE5C98767, 0xCF1FEBD2, 0x61EFC8C2, + 0xF1AC2571, 0xCC8239C2, 0x67214CB8, 0xB1E583D1, 0xB7DC3E62, 0x7F10BDCE, + 0xF90A5C38, 0x0FF0443D, 0x606E6DC6, 0x60543A49, 0x5727C148, 0x2BE98A1D, + 0x8AB41738, 0x20E1BE24, 0xAF96DA0F, 0x68458425, 0x99833BE5, 0x600D457D, + 0x282F9350, 0x8334B362, 0xD91D1120, 0x2B6D8DA0, 0x642B1E31, 0x9C305A00, + 0x52BCE688, 0x1B03588A, 0xF7BAEFD5, 0x4142ED9C, 0xA4315C11, 0x83323EC5, + 0xDFEF4636, 0xA133C501, 0xE9D3531C, 0xEE353783 }; + private static final int[] S4 = { + 0x9DB30420, 0x1FB6E9DE, 0xA7BE7BEF, 0xD273A298, 0x4A4F7BDB, 0x64AD8C57, + 0x85510443, 0xFA020ED1, 0x7E287AFF, 0xE60FB663, 0x095F35A1, 0x79EBF120, + 0xFD059D43, 0x6497B7B1, 0xF3641F63, 0x241E4ADF, 0x28147F5F, 0x4FA2B8CD, + 0xC9430040, 0x0CC32220, 0xFDD30B30, 0xC0A5374F, 0x1D2D00D9, 0x24147B15, + 0xEE4D111A, 0x0FCA5167, 0x71FF904C, 0x2D195FFE, 0x1A05645F, 0x0C13FEFE, + 0x081B08CA, 0x05170121, 0x80530100, 0xE83E5EFE, 0xAC9AF4F8, 0x7FE72701, + 0xD2B8EE5F, 0x06DF4261, 0xBB9E9B8A, 0x7293EA25, 0xCE84FFDF, 0xF5718801, + 0x3DD64B04, 0xA26F263B, 0x7ED48400, 0x547EEBE6, 0x446D4CA0, 0x6CF3D6F5, + 0x2649ABDF, 0xAEA0C7F5, 0x36338CC1, 0x503F7E93, 0xD3772061, 0x11B638E1, + 0x72500E03, 0xF80EB2BB, 0xABE0502E, 0xEC8D77DE, 0x57971E81, 0xE14F6746, + 0xC9335400, 0x6920318F, 0x081DBB99, 0xFFC304A5, 0x4D351805, 0x7F3D5CE3, + 0xA6C866C6, 0x5D5BCCA9, 0xDAEC6FEA, 0x9F926F91, 0x9F46222F, 0x3991467D, + 0xA5BF6D8E, 0x1143C44F, 0x43958302, 0xD0214EEB, 0x022083B8, 0x3FB6180C, + 0x18F8931E, 0x281658E6, 0x26486E3E, 0x8BD78A70, 0x7477E4C1, 0xB506E07C, + 0xF32D0A25, 0x79098B02, 0xE4EABB81, 0x28123B23, 0x69DEAD38, 0x1574CA16, + 0xDF871B62, 0x211C40B7, 0xA51A9EF9, 0x0014377B, 0x041E8AC8, 0x09114003, + 0xBD59E4D2, 0xE3D156D5, 0x4FE876D5, 0x2F91A340, 0x557BE8DE, 0x00EAE4A7, + 0x0CE5C2EC, 0x4DB4BBA6, 0xE756BDFF, 0xDD3369AC, 0xEC17B035, 0x06572327, + 0x99AFC8B0, 0x56C8C391, 0x6B65811C, 0x5E146119, 0x6E85CB75, 0xBE07C002, + 0xC2325577, 0x893FF4EC, 0x5BBFC92D, 0xD0EC3B25, 0xB7801AB7, 0x8D6D3B24, + 0x20C763EF, 0xC366A5FC, 0x9C382880, 0x0ACE3205, 0xAAC9548A, 0xECA1D7C7, + 0x041AFA32, 0x1D16625A, 0x6701902C, 0x9B757A54, 0x31D477F7, 0x9126B031, + 0x36CC6FDB, 0xC70B8B46, 0xD9E66A48, 0x56E55A79, 0x026A4CEB, 0x52437EFF, + 0x2F8F76B4, 0x0DF980A5, 0x8674CDE3, 0xEDDA04EB, 0x17A9BE04, 0x2C18F4DF, + 0xB7747F9D, 0xAB2AF7B4, 0xEFC34D20, 0x2E096B7C, 0x1741A254, 0xE5B6A035, + 0x213D42F6, 0x2C1C7C26, 0x61C2F50F, 0x6552DAF9, 0xD2C231F8, 0x25130F69, + 0xD8167FA2, 0x0418F2C8, 0x001A96A6, 0x0D1526AB, 0x63315C21, 0x5E0A72EC, + 0x49BAFEFD, 0x187908D9, 0x8D0DBD86, 0x311170A7, 0x3E9B640C, 0xCC3E10D7, + 0xD5CAD3B6, 0x0CAEC388, 0xF73001E1, 0x6C728AFF, 0x71EAE2A1, 0x1F9AF36E, + 0xCFCBD12F, 0xC1DE8417, 0xAC07BE6B, 0xCB44A1D8, 0x8B9B0F56, 0x013988C3, + 0xB1C52FCA, 0xB4BE31CD, 0xD8782806, 0x12A3A4E2, 0x6F7DE532, 0x58FD7EB6, + 0xD01EE900, 0x24ADFFC2, 0xF4990FC5, 0x9711AAC5, 0x001D7B95, 0x82E5E7D2, + 0x109873F6, 0x00613096, 0xC32D9521, 0xADA121FF, 0x29908415, 0x7FBB977F, + 0xAF9EB3DB, 0x29C9ED2A, 0x5CE2A465, 0xA730F32C, 0xD0AA3FE8, 0x8A5CC091, + 0xD49E2CE7, 0x0CE454A9, 0xD60ACD86, 0x015F1919, 0x77079103, 0xDEA03AF6, + 0x78A8565E, 0xDEE356DF, 0x21F05CBE, 0x8B75E387, 0xB3C50651, 0xB8A5C3EF, + 0xD8EEB6D2, 0xE523BE77, 0xC2154529, 0x2F69EFDF, 0xAFE67AFB, 0xF470C4B2, + 0xF3E0EB5B, 0xD6CC9876, 0x39E4460C, 0x1FDA8538, 0x1987832F, 0xCA007367, + 0xA99144F8, 0x296B299E, 0x492FC295, 0x9266BEAB, 0xB5676E69, 0x9BD3DDDA, + 0xDF7E052F, 0xDB25701C, 0x1B5E51EE, 0xF65324E6, 0x6AFCE36C, 0x0316CC04, + 0x8644213E, 0xB7DC59D0, 0x7965291F, 0xCCD6FD43, 0x41823979, 0x932BCDF6, + 0xB657C34D, 0x4EDFD282, 0x7AE5290C, 0x3CB9536B, 0x851E20FE, 0x9833557E, + 0x13ECF0B0, 0xD3FFB372, 0x3F85C5C1, 0x0AEF7ED2 }; + private static final int[] S5 = { + 0x7EC90C04, 0x2C6E74B9, 0x9B0E66DF, 0xA6337911, 0xB86A7FFF, 0x1DD358F5, + 0x44DD9D44, 0x1731167F, 0x08FBF1FA, 0xE7F511CC, 0xD2051B00, 0x735ABA00, + 0x2AB722D8, 0x386381CB, 0xACF6243A, 0x69BEFD7A, 0xE6A2E77F, 0xF0C720CD, + 0xC4494816, 0xCCF5C180, 0x38851640, 0x15B0A848, 0xE68B18CB, 0x4CAADEFF, + 0x5F480A01, 0x0412B2AA, 0x259814FC, 0x41D0EFE2, 0x4E40B48D, 0x248EB6FB, + 0x8DBA1CFE, 0x41A99B02, 0x1A550A04, 0xBA8F65CB, 0x7251F4E7, 0x95A51725, + 0xC106ECD7, 0x97A5980A, 0xC539B9AA, 0x4D79FE6A, 0xF2F3F763, 0x68AF8040, + 0xED0C9E56, 0x11B4958B, 0xE1EB5A88, 0x8709E6B0, 0xD7E07156, 0x4E29FEA7, + 0x6366E52D, 0x02D1C000, 0xC4AC8E05, 0x9377F571, 0x0C05372A, 0x578535F2, + 0x2261BE02, 0xD642A0C9, 0xDF13A280, 0x74B55BD2, 0x682199C0, 0xD421E5EC, + 0x53FB3CE8, 0xC8ADEDB3, 0x28A87FC9, 0x3D959981, 0x5C1FF900, 0xFE38D399, + 0x0C4EFF0B, 0x062407EA, 0xAA2F4FB1, 0x4FB96976, 0x90C79505, 0xB0A8A774, + 0xEF55A1FF, 0xE59CA2C2, 0xA6B62D27, 0xE66A4263, 0xDF65001F, 0x0EC50966, + 0xDFDD55BC, 0x29DE0655, 0x911E739A, 0x17AF8975, 0x32C7911C, 0x89F89468, + 0x0D01E980, 0x524755F4, 0x03B63CC9, 0x0CC844B2, 0xBCF3F0AA, 0x87AC36E9, + 0xE53A7426, 0x01B3D82B, 0x1A9E7449, 0x64EE2D7E, 0xCDDBB1DA, 0x01C94910, + 0xB868BF80, 0x0D26F3FD, 0x9342EDE7, 0x04A5C284, 0x636737B6, 0x50F5B616, + 0xF24766E3, 0x8ECA36C1, 0x136E05DB, 0xFEF18391, 0xFB887A37, 0xD6E7F7D4, + 0xC7FB7DC9, 0x3063FCDF, 0xB6F589DE, 0xEC2941DA, 0x26E46695, 0xB7566419, + 0xF654EFC5, 0xD08D58B7, 0x48925401, 0xC1BACB7F, 0xE5FF550F, 0xB6083049, + 0x5BB5D0E8, 0x87D72E5A, 0xAB6A6EE1, 0x223A66CE, 0xC62BF3CD, 0x9E0885F9, + 0x68CB3E47, 0x086C010F, 0xA21DE820, 0xD18B69DE, 0xF3F65777, 0xFA02C3F6, + 0x407EDAC3, 0xCBB3D550, 0x1793084D, 0xB0D70EBA, 0x0AB378D5, 0xD951FB0C, + 0xDED7DA56, 0x4124BBE4, 0x94CA0B56, 0x0F5755D1, 0xE0E1E56E, 0x6184B5BE, + 0x580A249F, 0x94F74BC0, 0xE327888E, 0x9F7B5561, 0xC3DC0280, 0x05687715, + 0x646C6BD7, 0x44904DB3, 0x66B4F0A3, 0xC0F1648A, 0x697ED5AF, 0x49E92FF6, + 0x309E374F, 0x2CB6356A, 0x85808573, 0x4991F840, 0x76F0AE02, 0x083BE84D, + 0x28421C9A, 0x44489406, 0x736E4CB8, 0xC1092910, 0x8BC95FC6, 0x7D869CF4, + 0x134F616F, 0x2E77118D, 0xB31B2BE1, 0xAA90B472, 0x3CA5D717, 0x7D161BBA, + 0x9CAD9010, 0xAF462BA2, 0x9FE459D2, 0x45D34559, 0xD9F2DA13, 0xDBC65487, + 0xF3E4F94E, 0x176D486F, 0x097C13EA, 0x631DA5C7, 0x445F7382, 0x175683F4, + 0xCDC66A97, 0x70BE0288, 0xB3CDCF72, 0x6E5DD2F3, 0x20936079, 0x459B80A5, + 0xBE60E2DB, 0xA9C23101, 0xEBA5315C, 0x224E42F2, 0x1C5C1572, 0xF6721B2C, + 0x1AD2FFF3, 0x8C25404E, 0x324ED72F, 0x4067B7FD, 0x0523138E, 0x5CA3BC78, + 0xDC0FD66E, 0x75922283, 0x784D6B17, 0x58EBB16E, 0x44094F85, 0x3F481D87, + 0xFCFEAE7B, 0x77B5FF76, 0x8C2302BF, 0xAAF47556, 0x5F46B02A, 0x2B092801, + 0x3D38F5F7, 0x0CA81F36, 0x52AF4A8A, 0x66D5E7C0, 0xDF3B0874, 0x95055110, + 0x1B5AD7A8, 0xF61ED5AD, 0x6CF6E479, 0x20758184, 0xD0CEFA65, 0x88F7BE58, + 0x4A046826, 0x0FF6F8F3, 0xA09C7F70, 0x5346ABA0, 0x5CE96C28, 0xE176EDA3, + 0x6BAC307F, 0x376829D2, 0x85360FA9, 0x17E3FE2A, 0x24B79767, 0xF5A96B20, + 0xD6CD2595, 0x68FF1EBF, 0x7555442C, 0xF19F06BE, 0xF9E0659A, 0xEEB9491D, + 0x34010718, 0xBB30CAB8, 0xE822FE15, 0x88570983, 0x750E6249, 0xDA627E55, + 0x5E76FFA8, 0xB1534546, 0x6D47DE08, 0xEFE9E7D4 }; + private static final int[] S6 = { + 0xF6FA8F9D, 0x2CAC6CE1, 0x4CA34867, 0xE2337F7C, 0x95DB08E7, 0x016843B4, + 0xECED5CBC, 0x325553AC, 0xBF9F0960, 0xDFA1E2ED, 0x83F0579D, 0x63ED86B9, + 0x1AB6A6B8, 0xDE5EBE39, 0xF38FF732, 0x8989B138, 0x33F14961, 0xC01937BD, + 0xF506C6DA, 0xE4625E7E, 0xA308EA99, 0x4E23E33C, 0x79CBD7CC, 0x48A14367, + 0xA3149619, 0xFEC94BD5, 0xA114174A, 0xEAA01866, 0xA084DB2D, 0x09A8486F, + 0xA888614A, 0x2900AF98, 0x01665991, 0xE1992863, 0xC8F30C60, 0x2E78EF3C, + 0xD0D51932, 0xCF0FEC14, 0xF7CA07D2, 0xD0A82072, 0xFD41197E, 0x9305A6B0, + 0xE86BE3DA, 0x74BED3CD, 0x372DA53C, 0x4C7F4448, 0xDAB5D440, 0x6DBA0EC3, + 0x083919A7, 0x9FBAEED9, 0x49DBCFB0, 0x4E670C53, 0x5C3D9C01, 0x64BDB941, + 0x2C0E636A, 0xBA7DD9CD, 0xEA6F7388, 0xE70BC762, 0x35F29ADB, 0x5C4CDD8D, + 0xF0D48D8C, 0xB88153E2, 0x08A19866, 0x1AE2EAC8, 0x284CAF89, 0xAA928223, + 0x9334BE53, 0x3B3A21BF, 0x16434BE3, 0x9AEA3906, 0xEFE8C36E, 0xF890CDD9, + 0x80226DAE, 0xC340A4A3, 0xDF7E9C09, 0xA694A807, 0x5B7C5ECC, 0x221DB3A6, + 0x9A69A02F, 0x68818A54, 0xCEB2296F, 0x53C0843A, 0xFE893655, 0x25BFE68A, + 0xB4628ABC, 0xCF222EBF, 0x25AC6F48, 0xA9A99387, 0x53BDDB65, 0xE76FFBE7, + 0xE967FD78, 0x0BA93563, 0x8E342BC1, 0xE8A11BE9, 0x4980740D, 0xC8087DFC, + 0x8DE4BF99, 0xA11101A0, 0x7FD37975, 0xDA5A26C0, 0xE81F994F, 0x9528CD89, + 0xFD339FED, 0xB87834BF, 0x5F04456D, 0x22258698, 0xC9C4C83B, 0x2DC156BE, + 0x4F628DAA, 0x57F55EC5, 0xE2220ABE, 0xD2916EBF, 0x4EC75B95, 0x24F2C3C0, + 0x42D15D99, 0xCD0D7FA0, 0x7B6E27FF, 0xA8DC8AF0, 0x7345C106, 0xF41E232F, + 0x35162386, 0xE6EA8926, 0x3333B094, 0x157EC6F2, 0x372B74AF, 0x692573E4, + 0xE9A9D848, 0xF3160289, 0x3A62EF1D, 0xA787E238, 0xF3A5F676, 0x74364853, + 0x20951063, 0x4576698D, 0xB6FAD407, 0x592AF950, 0x36F73523, 0x4CFB6E87, + 0x7DA4CEC0, 0x6C152DAA, 0xCB0396A8, 0xC50DFE5D, 0xFCD707AB, 0x0921C42F, + 0x89DFF0BB, 0x5FE2BE78, 0x448F4F33, 0x754613C9, 0x2B05D08D, 0x48B9D585, + 0xDC049441, 0xC8098F9B, 0x7DEDE786, 0xC39A3373, 0x42410005, 0x6A091751, + 0x0EF3C8A6, 0x890072D6, 0x28207682, 0xA9A9F7BE, 0xBF32679D, 0xD45B5B75, + 0xB353FD00, 0xCBB0E358, 0x830F220A, 0x1F8FB214, 0xD372CF08, 0xCC3C4A13, + 0x8CF63166, 0x061C87BE, 0x88C98F88, 0x6062E397, 0x47CF8E7A, 0xB6C85283, + 0x3CC2ACFB, 0x3FC06976, 0x4E8F0252, 0x64D8314D, 0xDA3870E3, 0x1E665459, + 0xC10908F0, 0x513021A5, 0x6C5B68B7, 0x822F8AA0, 0x3007CD3E, 0x74719EEF, + 0xDC872681, 0x073340D4, 0x7E432FD9, 0x0C5EC241, 0x8809286C, 0xF592D891, + 0x08A930F6, 0x957EF305, 0xB7FBFFBD, 0xC266E96F, 0x6FE4AC98, 0xB173ECC0, + 0xBC60B42A, 0x953498DA, 0xFBA1AE12, 0x2D4BD736, 0x0F25FAAB, 0xA4F3FCEB, + 0xE2969123, 0x257F0C3D, 0x9348AF49, 0x361400BC, 0xE8816F4A, 0x3814F200, + 0xA3F94043, 0x9C7A54C2, 0xBC704F57, 0xDA41E7F9, 0xC25AD33A, 0x54F4A084, + 0xB17F5505, 0x59357CBE, 0xEDBD15C8, 0x7F97C5AB, 0xBA5AC7B5, 0xB6F6DEAF, + 0x3A479C3A, 0x5302DA25, 0x653D7E6A, 0x54268D49, 0x51A477EA, 0x5017D55B, + 0xD7D25D88, 0x44136C76, 0x0404A8C8, 0xB8E5A121, 0xB81A928A, 0x60ED5869, + 0x97C55B96, 0xEAEC991B, 0x29935913, 0x01FDB7F1, 0x088E8DFA, 0x9AB6F6F5, + 0x3B4CBF9F, 0x4A5DE3AB, 0xE6051D35, 0xA0E1D855, 0xD36B4CF1, 0xF544EDEB, + 0xB0E93524, 0xBEBB8FBD, 0xA2D762CF, 0x49C92F54, 0x38B5F331, 0x7128A454, + 0x48392905, 0xA65B1DB8, 0x851C97BD, 0xD675CF2F }; + private static final int[] S7 = { + 0x85E04019, 0x332BF567, 0x662DBFFF, 0xCFC65693, 0x2A8D7F6F, 0xAB9BC912, + 0xDE6008A1, 0x2028DA1F, 0x0227BCE7, 0x4D642916, 0x18FAC300, 0x50F18B82, + 0x2CB2CB11, 0xB232E75C, 0x4B3695F2, 0xB28707DE, 0xA05FBCF6, 0xCD4181E9, + 0xE150210C, 0xE24EF1BD, 0xB168C381, 0xFDE4E789, 0x5C79B0D8, 0x1E8BFD43, + 0x4D495001, 0x38BE4341, 0x913CEE1D, 0x92A79C3F, 0x089766BE, 0xBAEEADF4, + 0x1286BECF, 0xB6EACB19, 0x2660C200, 0x7565BDE4, 0x64241F7A, 0x8248DCA9, + 0xC3B3AD66, 0x28136086, 0x0BD8DFA8, 0x356D1CF2, 0x107789BE, 0xB3B2E9CE, + 0x0502AA8F, 0x0BC0351E, 0x166BF52A, 0xEB12FF82, 0xE3486911, 0xD34D7516, + 0x4E7B3AFF, 0x5F43671B, 0x9CF6E037, 0x4981AC83, 0x334266CE, 0x8C9341B7, + 0xD0D854C0, 0xCB3A6C88, 0x47BC2829, 0x4725BA37, 0xA66AD22B, 0x7AD61F1E, + 0x0C5CBAFA, 0x4437F107, 0xB6E79962, 0x42D2D816, 0x0A961288, 0xE1A5C06E, + 0x13749E67, 0x72FC081A, 0xB1D139F7, 0xF9583745, 0xCF19DF58, 0xBEC3F756, + 0xC06EBA30, 0x07211B24, 0x45C28829, 0xC95E317F, 0xBC8EC511, 0x38BC46E9, + 0xC6E6FA14, 0xBAE8584A, 0xAD4EBC46, 0x468F508B, 0x7829435F, 0xF124183B, + 0x821DBA9F, 0xAFF60FF4, 0xEA2C4E6D, 0x16E39264, 0x92544A8B, 0x009B4FC3, + 0xABA68CED, 0x9AC96F78, 0x06A5B79A, 0xB2856E6E, 0x1AEC3CA9, 0xBE838688, + 0x0E0804E9, 0x55F1BE56, 0xE7E5363B, 0xB3A1F25D, 0xF7DEBB85, 0x61FE033C, + 0x16746233, 0x3C034C28, 0xDA6D0C74, 0x79AAC56C, 0x3CE4E1AD, 0x51F0C802, + 0x98F8F35A, 0x1626A49F, 0xEED82B29, 0x1D382FE3, 0x0C4FB99A, 0xBB325778, + 0x3EC6D97B, 0x6E77A6A9, 0xCB658B5C, 0xD45230C7, 0x2BD1408B, 0x60C03EB7, + 0xB9068D78, 0xA33754F4, 0xF430C87D, 0xC8A71302, 0xB96D8C32, 0xEBD4E7BE, + 0xBE8B9D2D, 0x7979FB06, 0xE7225308, 0x8B75CF77, 0x11EF8DA4, 0xE083C858, + 0x8D6B786F, 0x5A6317A6, 0xFA5CF7A0, 0x5DDA0033, 0xF28EBFB0, 0xF5B9C310, + 0xA0EAC280, 0x08B9767A, 0xA3D9D2B0, 0x79D34217, 0x021A718D, 0x9AC6336A, + 0x2711FD60, 0x438050E3, 0x069908A8, 0x3D7FEDC4, 0x826D2BEF, 0x4EEB8476, + 0x488DCF25, 0x36C9D566, 0x28E74E41, 0xC2610ACA, 0x3D49A9CF, 0xBAE3B9DF, + 0xB65F8DE6, 0x92AEAF64, 0x3AC7D5E6, 0x9EA80509, 0xF22B017D, 0xA4173F70, + 0xDD1E16C3, 0x15E0D7F9, 0x50B1B887, 0x2B9F4FD5, 0x625ABA82, 0x6A017962, + 0x2EC01B9C, 0x15488AA9, 0xD716E740, 0x40055A2C, 0x93D29A22, 0xE32DBF9A, + 0x058745B9, 0x3453DC1E, 0xD699296E, 0x496CFF6F, 0x1C9F4986, 0xDFE2ED07, + 0xB87242D1, 0x19DE7EAE, 0x053E561A, 0x15AD6F8C, 0x66626C1C, 0x7154C24C, + 0xEA082B2A, 0x93EB2939, 0x17DCB0F0, 0x58D4F2AE, 0x9EA294FB, 0x52CF564C, + 0x9883FE66, 0x2EC40581, 0x763953C3, 0x01D6692E, 0xD3A0C108, 0xA1E7160E, + 0xE4F2DFA6, 0x693ED285, 0x74904698, 0x4C2B0EDD, 0x4F757656, 0x5D393378, + 0xA132234F, 0x3D321C5D, 0xC3F5E194, 0x4B269301, 0xC79F022F, 0x3C997E7E, + 0x5E4F9504, 0x3FFAFBBD, 0x76F7AD0E, 0x296693F4, 0x3D1FCE6F, 0xC61E45BE, + 0xD3B5AB34, 0xF72BF9B7, 0x1B0434C0, 0x4E72B567, 0x5592A33D, 0xB5229301, + 0xCFD2A87F, 0x60AEB767, 0x1814386B, 0x30BCC33D, 0x38A0C07D, 0xFD1606F2, + 0xC363519B, 0x589DD390, 0x5479F8E6, 0x1CB8D647, 0x97FD61A9, 0xEA7759F4, + 0x2D57539D, 0x569A58CF, 0xE84E63AD, 0x462E1B78, 0x6580F87E, 0xF3817914, + 0x91DA55F4, 0x40A230F3, 0xD1988F35, 0xB6E318D2, 0x3FFA50BC, 0x3D40F021, + 0xC3C0BDAE, 0x4958C24C, 0x518F36B2, 0x84B1D370, 0x0FEDCE83, 0x878DDADA, + 0xF2A279C7, 0x94E01BE8, 0x90716F4B, 0x954B8AA3 }; + private static final int[] S8 = { + 0xE216300D, 0xBBDDFFFC, 0xA7EBDABD, 0x35648095, 0x7789F8B7, 0xE6C1121B, + 0x0E241600, 0x052CE8B5, 0x11A9CFB0, 0xE5952F11, 0xECE7990A, 0x9386D174, + 0x2A42931C, 0x76E38111, 0xB12DEF3A, 0x37DDDDFC, 0xDE9ADEB1, 0x0A0CC32C, + 0xBE197029, 0x84A00940, 0xBB243A0F, 0xB4D137CF, 0xB44E79F0, 0x049EEDFD, + 0x0B15A15D, 0x480D3168, 0x8BBBDE5A, 0x669DED42, 0xC7ECE831, 0x3F8F95E7, + 0x72DF191B, 0x7580330D, 0x94074251, 0x5C7DCDFA, 0xABBE6D63, 0xAA402164, + 0xB301D40A, 0x02E7D1CA, 0x53571DAE, 0x7A3182A2, 0x12A8DDEC, 0xFDAA335D, + 0x176F43E8, 0x71FB46D4, 0x38129022, 0xCE949AD4, 0xB84769AD, 0x965BD862, + 0x82F3D055, 0x66FB9767, 0x15B80B4E, 0x1D5B47A0, 0x4CFDE06F, 0xC28EC4B8, + 0x57E8726E, 0x647A78FC, 0x99865D44, 0x608BD593, 0x6C200E03, 0x39DC5FF6, + 0x5D0B00A3, 0xAE63AFF2, 0x7E8BD632, 0x70108C0C, 0xBBD35049, 0x2998DF04, + 0x980CF42A, 0x9B6DF491, 0x9E7EDD53, 0x06918548, 0x58CB7E07, 0x3B74EF2E, + 0x522FFFB1, 0xD24708CC, 0x1C7E27CD, 0xA4EB215B, 0x3CF1D2E2, 0x19B47A38, + 0x424F7618, 0x35856039, 0x9D17DEE7, 0x27EB35E6, 0xC9AFF67B, 0x36BAF5B8, + 0x09C467CD, 0xC18910B1, 0xE11DBF7B, 0x06CD1AF8, 0x7170C608, 0x2D5E3354, + 0xD4DE495A, 0x64C6D006, 0xBCC0C62C, 0x3DD00DB3, 0x708F8F34, 0x77D51B42, + 0x264F620F, 0x24B8D2BF, 0x15C1B79E, 0x46A52564, 0xF8D7E54E, 0x3E378160, + 0x7895CDA5, 0x859C15A5, 0xE6459788, 0xC37BC75F, 0xDB07BA0C, 0x0676A3AB, + 0x7F229B1E, 0x31842E7B, 0x24259FD7, 0xF8BEF472, 0x835FFCB8, 0x6DF4C1F2, + 0x96F5B195, 0xFD0AF0FC, 0xB0FE134C, 0xE2506D3D, 0x4F9B12EA, 0xF215F225, + 0xA223736F, 0x9FB4C428, 0x25D04979, 0x34C713F8, 0xC4618187, 0xEA7A6E98, + 0x7CD16EFC, 0x1436876C, 0xF1544107, 0xBEDEEE14, 0x56E9AF27, 0xA04AA441, + 0x3CF7C899, 0x92ECBAE6, 0xDD67016D, 0x151682EB, 0xA842EEDF, 0xFDBA60B4, + 0xF1907B75, 0x20E3030F, 0x24D8C29E, 0xE139673B, 0xEFA63FB8, 0x71873054, + 0xB6F2CF3B, 0x9F326442, 0xCB15A4CC, 0xB01A4504, 0xF1E47D8D, 0x844A1BE5, + 0xBAE7DFDC, 0x42CBDA70, 0xCD7DAE0A, 0x57E85B7A, 0xD53F5AF6, 0x20CF4D8C, + 0xCEA4D428, 0x79D130A4, 0x3486EBFB, 0x33D3CDDC, 0x77853B53, 0x37EFFCB5, + 0xC5068778, 0xE580B3E6, 0x4E68B8F4, 0xC5C8B37E, 0x0D809EA2, 0x398FEB7C, + 0x132A4F94, 0x43B7950E, 0x2FEE7D1C, 0x223613BD, 0xDD06CAA2, 0x37DF932B, + 0xC4248289, 0xACF3EBC3, 0x5715F6B7, 0xEF3478DD, 0xF267616F, 0xC148CBE4, + 0x9052815E, 0x5E410FAB, 0xB48A2465, 0x2EDA7FA4, 0xE87B40E4, 0xE98EA084, + 0x5889E9E1, 0xEFD390FC, 0xDD07D35B, 0xDB485694, 0x38D7E5B2, 0x57720101, + 0x730EDEBC, 0x5B643113, 0x94917E4F, 0x503C2FBA, 0x646F1282, 0x7523D24A, + 0xE0779695, 0xF9C17A8F, 0x7A5B2121, 0xD187B896, 0x29263A4D, 0xBA510CDF, + 0x81F47C9F, 0xAD1163ED, 0xEA7B5965, 0x1A00726E, 0x11403092, 0x00DA6D77, + 0x4A0CDD61, 0xAD1F4603, 0x605BDFB0, 0x9EEDC364, 0x22EBE6A8, 0xCEE7D28A, + 0xA0E736A0, 0x5564A6B9, 0x10853209, 0xC7EB8F37, 0x2DE705CA, 0x8951570F, + 0xDF09822B, 0xBD691A6C, 0xAA12E4F2, 0x87451C0F, 0xE0F6A27A, 0x3ADA4819, + 0x4CF1764F, 0x0D771C2B, 0x67CDB156, 0x350D8384, 0x5938FA0F, 0x42399EF3, + 0x36997B07, 0x0E84093D, 0x4AA93E61, 0x8360D87B, 0x1FA98B0C, 0x1149382C, + 0xE97625A5, 0x0614D1B7, 0x0E25244B, 0x0C768347, 0x589E8D82, 0x0D2059D1, + 0xA466BB1E, 0xF8DA0A82, 0x04F19130, 0xBA6E4EC0, 0x99265164, 0x1EE7230D, + 0x50B2AD80, 0xEAEE6801, 0x8DB2A283, 0xEA8BF59E }; + private static final int _12_ROUNDS = 12; + private static final int _16_ROUNDS = 16; + + /** Trivial 0-arguments constructor. */ + public Cast5() + { + super(Registry.CAST5_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + /** + * Assuming the input is a 32-bit block organised as: b31b30b29...b0, this + * method returns an array of 4 Java ints, containing from position 0 onward + * the values: {b31b30b29b28, b27b26b25b24, ... , b3b2b1b0}. + * + * @param x a 32-bit block. + * @return an array of 4 ints, each being the contents of an 8-bit block from + * the input. + */ + private static final int[] unscramble(int x) + { + return new int[] { x >>> 24, (x >>> 16) & 0xFF, (x >>> 8) & 0xFF, x & 0xFF }; + } + + public Object clone() + { + Cast5 result = new Cast5(); + result.currentBlockSize = this.currentBlockSize; + return result; + } + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(DEFAULT_BLOCK_SIZE)); + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + for (int n = 5; n < 17; n++) + al.add(Integer.valueOf(n)); + return Collections.unmodifiableList(al).iterator(); + } + + public Object makeKey(byte[] uk, int bs) throws InvalidKeyException + { + if (bs != DEFAULT_BLOCK_SIZE) + throw new IllegalArgumentException(); + if (uk == null) + throw new InvalidKeyException("Empty key"); + int len = uk.length; + if (len < 5 || len > 16) + throw new InvalidKeyException("Key size (in bytes) is not in the range [5..16]"); + Cast5Key result = new Cast5Key(); + result.rounds = (len < 11) ? _12_ROUNDS : _16_ROUNDS; + byte[] kk = new byte[16]; + System.arraycopy(uk, 0, kk, 0, len); + int z0z1z2z3, z4z5z6z7, z8z9zAzB, zCzDzEzF; + int z0, z1, z2, z3, z4, z5, z6, z7, z8, z9, zA, zB, zC, zD, zE, zF; + int x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, xA, xB, xC, xD, xE, xF; + int[] b; + int x0x1x2x3 = kk[0 ] << 24 + | (kk[1 ] & 0xFF) << 16 + | (kk[2 ] & 0xFF) << 8 + | (kk[3 ] & 0xFF); + int x4x5x6x7 = kk[4 ] << 24 + | (kk[5 ] & 0xFF) << 16 + | (kk[6 ] & 0xFF) << 8 + | (kk[7 ] & 0xFF); + int x8x9xAxB = kk[8 ] << 24 + | (kk[9 ] & 0xFF) << 16 + | (kk[10] & 0xFF) << 8 + | (kk[11] & 0xFF); + int xCxDxExF = kk[12] << 24 + | (kk[13] & 0xFF) << 16 + | (kk[14] & 0xFF) << 8 + | (kk[15] & 0xFF); + b = unscramble(x0x1x2x3); + x0 = b[0]; + x1 = b[1]; + x2 = b[2]; + x3 = b[3]; + b = unscramble(x4x5x6x7); + x4 = b[0]; + x5 = b[1]; + x6 = b[2]; + x7 = b[3]; + b = unscramble(x8x9xAxB); + x8 = b[0]; + x9 = b[1]; + xA = b[2]; + xB = b[3]; + b = unscramble(xCxDxExF); + xC = b[0]; + xD = b[1]; + xE = b[2]; + xF = b[3]; + z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8]; + b = unscramble(z0z1z2z3); + z0 = b[0]; + z1 = b[1]; + z2 = b[2]; + z3 = b[3]; + z4z5z6z7 = x8x9xAxB ^ S5[z0] ^ S6[z2] ^ S7[z1] ^ S8[z3] ^ S8[xA]; + b = unscramble(z4z5z6z7); + z4 = b[0]; + z5 = b[1]; + z6 = b[2]; + z7 = b[3]; + z8z9zAzB = xCxDxExF ^ S5[z7] ^ S6[z6] ^ S7[z5] ^ S8[z4] ^ S5[x9]; + b = unscramble(z8z9zAzB); + z8 = b[0]; + z9 = b[1]; + zA = b[2]; + zB = b[3]; + zCzDzEzF = x4x5x6x7 ^ S5[zA] ^ S6[z9] ^ S7[zB] ^ S8[z8] ^ S6[xB]; + b = unscramble(zCzDzEzF); + zC = b[0]; + zD = b[1]; + zE = b[2]; + zF = b[3]; + result.Km0 = S5[z8] ^ S6[z9] ^ S7[z7] ^ S8[z6] ^ S5[z2]; + result.Km1 = S5[zA] ^ S6[zB] ^ S7[z5] ^ S8[z4] ^ S6[z6]; + result.Km2 = S5[zC] ^ S6[zD] ^ S7[z3] ^ S8[z2] ^ S7[z9]; + result.Km3 = S5[zE] ^ S6[zF] ^ S7[z1] ^ S8[z0] ^ S8[zC]; + x0x1x2x3 = z8z9zAzB ^ S5[z5] ^ S6[z7] ^ S7[z4] ^ S8[z6] ^ S7[z0]; + b = unscramble(x0x1x2x3); + x0 = b[0]; + x1 = b[1]; + x2 = b[2]; + x3 = b[3]; + x4x5x6x7 = z0z1z2z3 ^ S5[x0] ^ S6[x2] ^ S7[x1] ^ S8[x3] ^ S8[z2]; + b = unscramble(x4x5x6x7); + x4 = b[0]; + x5 = b[1]; + x6 = b[2]; + x7 = b[3]; + x8x9xAxB = z4z5z6z7 ^ S5[x7] ^ S6[x6] ^ S7[x5] ^ S8[x4] ^ S5[z1]; + b = unscramble(x8x9xAxB); + x8 = b[0]; + x9 = b[1]; + xA = b[2]; + xB = b[3]; + xCxDxExF = zCzDzEzF ^ S5[xA] ^ S6[x9] ^ S7[xB] ^ S8[x8] ^ S6[z3]; + b = unscramble(xCxDxExF); + xC = b[0]; + xD = b[1]; + xE = b[2]; + xF = b[3]; + result.Km4 = S5[x3] ^ S6[x2] ^ S7[xC] ^ S8[xD] ^ S5[x8]; + result.Km5 = S5[x1] ^ S6[x0] ^ S7[xE] ^ S8[xF] ^ S6[xD]; + result.Km6 = S5[x7] ^ S6[x6] ^ S7[x8] ^ S8[x9] ^ S7[x3]; + result.Km7 = S5[x5] ^ S6[x4] ^ S7[xA] ^ S8[xB] ^ S8[x7]; + z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8]; + b = unscramble(z0z1z2z3); + z0 = b[0]; + z1 = b[1]; + z2 = b[2]; + z3 = b[3]; + z4z5z6z7 = x8x9xAxB ^ S5[z0] ^ S6[z2] ^ S7[z1] ^ S8[z3] ^ S8[xA]; + b = unscramble(z4z5z6z7); + z4 = b[0]; + z5 = b[1]; + z6 = b[2]; + z7 = b[3]; + z8z9zAzB = xCxDxExF ^ S5[z7] ^ S6[z6] ^ S7[z5] ^ S8[z4] ^ S5[x9]; + b = unscramble(z8z9zAzB); + z8 = b[0]; + z9 = b[1]; + zA = b[2]; + zB = b[3]; + zCzDzEzF = x4x5x6x7 ^ S5[zA] ^ S6[z9] ^ S7[zB] ^ S8[z8] ^ S6[xB]; + b = unscramble(zCzDzEzF); + zC = b[0]; + zD = b[1]; + zE = b[2]; + zF = b[3]; + result.Km8 = S5[z3] ^ S6[z2] ^ S7[zC] ^ S8[zD] ^ S5[z9]; + result.Km9 = S5[z1] ^ S6[z0] ^ S7[zE] ^ S8[zF] ^ S6[zC]; + result.Km10 = S5[z7] ^ S6[z6] ^ S7[z8] ^ S8[z9] ^ S7[z2]; + result.Km11 = S5[z5] ^ S6[z4] ^ S7[zA] ^ S8[zB] ^ S8[z6]; + x0x1x2x3 = z8z9zAzB ^ S5[z5] ^ S6[z7] ^ S7[z4] ^ S8[z6] ^ S7[z0]; + b = unscramble(x0x1x2x3); + x0 = b[0]; + x1 = b[1]; + x2 = b[2]; + x3 = b[3]; + x4x5x6x7 = z0z1z2z3 ^ S5[x0] ^ S6[x2] ^ S7[x1] ^ S8[x3] ^ S8[z2]; + b = unscramble(x4x5x6x7); + x4 = b[0]; + x5 = b[1]; + x6 = b[2]; + x7 = b[3]; + x8x9xAxB = z4z5z6z7 ^ S5[x7] ^ S6[x6] ^ S7[x5] ^ S8[x4] ^ S5[z1]; + b = unscramble(x8x9xAxB); + x8 = b[0]; + x9 = b[1]; + xA = b[2]; + xB = b[3]; + xCxDxExF = zCzDzEzF ^ S5[xA] ^ S6[x9] ^ S7[xB] ^ S8[x8] ^ S6[z3]; + b = unscramble(xCxDxExF); + xC = b[0]; + xD = b[1]; + xE = b[2]; + xF = b[3]; + result.Km12 = S5[x8] ^ S6[x9] ^ S7[x7] ^ S8[x6] ^ S5[x3]; + result.Km13 = S5[xA] ^ S6[xB] ^ S7[x5] ^ S8[x4] ^ S6[x7]; + result.Km14 = S5[xC] ^ S6[xD] ^ S7[x3] ^ S8[x2] ^ S7[x8]; + result.Km15 = S5[xE] ^ S6[xF] ^ S7[x1] ^ S8[x0] ^ S8[xD]; + // The remaining half is identical to what is given above, carrying on + // from the last created x0..xF to generate keys K17 - K32. These keys + // will be used as the 'rotation' keys and as such only the five least + // significant bits are to be considered. + z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8]; + b = unscramble(z0z1z2z3); + z0 = b[0]; + z1 = b[1]; + z2 = b[2]; + z3 = b[3]; + z4z5z6z7 = x8x9xAxB ^ S5[z0] ^ S6[z2] ^ S7[z1] ^ S8[z3] ^ S8[xA]; + b = unscramble(z4z5z6z7); + z4 = b[0]; + z5 = b[1]; + z6 = b[2]; + z7 = b[3]; + z8z9zAzB = xCxDxExF ^ S5[z7] ^ S6[z6] ^ S7[z5] ^ S8[z4] ^ S5[x9]; + b = unscramble(z8z9zAzB); + z8 = b[0]; + z9 = b[1]; + zA = b[2]; + zB = b[3]; + zCzDzEzF = x4x5x6x7 ^ S5[zA] ^ S6[z9] ^ S7[zB] ^ S8[z8] ^ S6[xB]; + b = unscramble(zCzDzEzF); + zC = b[0]; + zD = b[1]; + zE = b[2]; + zF = b[3]; + result.Kr0 = (S5[z8] ^ S6[z9] ^ S7[z7] ^ S8[z6] ^ S5[z2]) & 0x1F; + result.Kr1 = (S5[zA] ^ S6[zB] ^ S7[z5] ^ S8[z4] ^ S6[z6]) & 0x1F; + result.Kr2 = (S5[zC] ^ S6[zD] ^ S7[z3] ^ S8[z2] ^ S7[z9]) & 0x1F; + result.Kr3 = (S5[zE] ^ S6[zF] ^ S7[z1] ^ S8[z0] ^ S8[zC]) & 0x1F; + x0x1x2x3 = z8z9zAzB ^ S5[z5] ^ S6[z7] ^ S7[z4] ^ S8[z6] ^ S7[z0]; + b = unscramble(x0x1x2x3); + x0 = b[0]; + x1 = b[1]; + x2 = b[2]; + x3 = b[3]; + x4x5x6x7 = z0z1z2z3 ^ S5[x0] ^ S6[x2] ^ S7[x1] ^ S8[x3] ^ S8[z2]; + b = unscramble(x4x5x6x7); + x4 = b[0]; + x5 = b[1]; + x6 = b[2]; + x7 = b[3]; + x8x9xAxB = z4z5z6z7 ^ S5[x7] ^ S6[x6] ^ S7[x5] ^ S8[x4] ^ S5[z1]; + b = unscramble(x8x9xAxB); + x8 = b[0]; + x9 = b[1]; + xA = b[2]; + xB = b[3]; + xCxDxExF = zCzDzEzF ^ S5[xA] ^ S6[x9] ^ S7[xB] ^ S8[x8] ^ S6[z3]; + b = unscramble(xCxDxExF); + xC = b[0]; + xD = b[1]; + xE = b[2]; + xF = b[3]; + result.Kr4 = (S5[x3] ^ S6[x2] ^ S7[xC] ^ S8[xD] ^ S5[x8]) & 0x1F; + result.Kr5 = (S5[x1] ^ S6[x0] ^ S7[xE] ^ S8[xF] ^ S6[xD]) & 0x1F; + result.Kr6 = (S5[x7] ^ S6[x6] ^ S7[x8] ^ S8[x9] ^ S7[x3]) & 0x1F; + result.Kr7 = (S5[x5] ^ S6[x4] ^ S7[xA] ^ S8[xB] ^ S8[x7]) & 0x1F; + z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8]; + b = unscramble(z0z1z2z3); + z0 = b[0]; + z1 = b[1]; + z2 = b[2]; + z3 = b[3]; + z4z5z6z7 = x8x9xAxB ^ S5[z0] ^ S6[z2] ^ S7[z1] ^ S8[z3] ^ S8[xA]; + b = unscramble(z4z5z6z7); + z4 = b[0]; + z5 = b[1]; + z6 = b[2]; + z7 = b[3]; + z8z9zAzB = xCxDxExF ^ S5[z7] ^ S6[z6] ^ S7[z5] ^ S8[z4] ^ S5[x9]; + b = unscramble(z8z9zAzB); + z8 = b[0]; + z9 = b[1]; + zA = b[2]; + zB = b[3]; + zCzDzEzF = x4x5x6x7 ^ S5[zA] ^ S6[z9] ^ S7[zB] ^ S8[z8] ^ S6[xB]; + b = unscramble(zCzDzEzF); + zC = b[0]; + zD = b[1]; + zE = b[2]; + zF = b[3]; + result.Kr8 = (S5[z3] ^ S6[z2] ^ S7[zC] ^ S8[zD] ^ S5[z9]) & 0x1F; + result.Kr9 = (S5[z1] ^ S6[z0] ^ S7[zE] ^ S8[zF] ^ S6[zC]) & 0x1F; + result.Kr10 = (S5[z7] ^ S6[z6] ^ S7[z8] ^ S8[z9] ^ S7[z2]) & 0x1F; + result.Kr11 = (S5[z5] ^ S6[z4] ^ S7[zA] ^ S8[zB] ^ S8[z6]) & 0x1F; + x0x1x2x3 = z8z9zAzB ^ S5[z5] ^ S6[z7] ^ S7[z4] ^ S8[z6] ^ S7[z0]; + b = unscramble(x0x1x2x3); + x0 = b[0]; + x1 = b[1]; + x2 = b[2]; + x3 = b[3]; + x4x5x6x7 = z0z1z2z3 ^ S5[x0] ^ S6[x2] ^ S7[x1] ^ S8[x3] ^ S8[z2]; + b = unscramble(x4x5x6x7); + x4 = b[0]; + x5 = b[1]; + x6 = b[2]; + x7 = b[3]; + x8x9xAxB = z4z5z6z7 ^ S5[x7] ^ S6[x6] ^ S7[x5] ^ S8[x4] ^ S5[z1]; + b = unscramble(x8x9xAxB); + x8 = b[0]; + x9 = b[1]; + xA = b[2]; + xB = b[3]; + xCxDxExF = zCzDzEzF ^ S5[xA] ^ S6[x9] ^ S7[xB] ^ S8[x8] ^ S6[z3]; + b = unscramble(xCxDxExF); + xC = b[0]; + xD = b[1]; + xE = b[2]; + xF = b[3]; + result.Kr12 = (S5[x8] ^ S6[x9] ^ S7[x7] ^ S8[x6] ^ S5[x3]) & 0x1F; + result.Kr13 = (S5[xA] ^ S6[xB] ^ S7[x5] ^ S8[x4] ^ S6[x7]) & 0x1F; + result.Kr14 = (S5[xC] ^ S6[xD] ^ S7[x3] ^ S8[x2] ^ S7[x8]) & 0x1F; + result.Kr15 = (S5[xE] ^ S6[xF] ^ S7[x1] ^ S8[x0] ^ S8[xD]) & 0x1F; + return result; + } + + /** + * The full encryption algorithm is given in the following four steps. + *
+   *    INPUT:  plaintext m1...m64; key K = k1...k128.
+   *    OUTPUT: ciphertext c1...c64.
+   * 
+ *
    + *
  1. (key schedule) Compute 16 pairs of subkeys {Kmi, Kri} from a user + * key (see makeKey() method).
  2. + *
  3. (L0,R0) <-- (m1...m64). (Split the plaintext into left and right + * 32-bit halves L0 = m1...m32 and R0 = m33...m64.).
  4. + *
  5. (16 rounds) for i from 1 to 16, compute Li and Ri as follows: + *
      + *
    • Li = Ri-1;
    • + *
    • Ri = Li-1 ^ F(Ri-1,Kmi,Kri), where F is defined in method F() -- + * f is of Type 1, Type 2, or Type 3, depending on i, and ^ being the + * bitwise XOR function.
    • + *
    + *
  6. c1...c64 <-- (R16,L16). (Exchange final blocks L16, R16 and + * concatenate to form the ciphertext.)
  7. + *
+ *

+ * Decryption is identical to the encryption algorithm given above, except + * that the rounds (and therefore the subkey pairs) are used in reverse order + * to compute (L0,R0) from (R16,L16). + *

+ * Looking at the iterations/rounds in pairs we have: + *

+   *    (1a)    Li = Ri-1;
+   *    (1b)    Ri = Li-1 ^ Fi(Ri-1);
+   *    (2a)    Li+1 = Ri;
+   *    (2b)    Ri+1 = Li ^ Fi+1(Ri);
+   * 
+ * which by substituting (2a) in (2b) becomes + *
+   *    (2c)    Ri+1 = Li ^ Fi+1(Li+1);
+   * 
+ * by substituting (1b) in (2a) and (1a) in (2c), we get: + *
+   *    (3a)    Li+1 = Li-1 ^ Fi(Ri-1);
+   *    (3b)    Ri+1 = Ri-1 ^ Fi+1(Li+1);
+   * 
+ * Using only one couple of variables L and R, initialised to L0 and R0 + * respectively, the assignments for each pair of rounds become: + *
+   *    (4a)    L ^= Fi(R);
+   *    (4b)    R ^= Fi+1(L);
+   * 
+ * + * @param in contains the plain-text 64-bit block. + * @param i start index within input where data is considered. + * @param out will contain the cipher-text block. + * @param j index in out where cipher-text starts. + * @param k the session key object. + * @param bs the desired block size. + */ + public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + if (bs != DEFAULT_BLOCK_SIZE) + throw new IllegalArgumentException(); + Cast5Key K = (Cast5Key) k; + int L = (in[i++] & 0xFF) << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | in[i++] & 0xFF; + int R = (in[i++] & 0xFF) << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | in[i ] & 0xFF; + L ^= f1(R, K.Km0, K.Kr0); + R ^= f2(L, K.Km1, K.Kr1); // round 2 + L ^= f3(R, K.Km2, K.Kr2); + R ^= f1(L, K.Km3, K.Kr3); // round 4 + L ^= f2(R, K.Km4, K.Kr4); + R ^= f3(L, K.Km5, K.Kr5); // round 6 + L ^= f1(R, K.Km6, K.Kr6); + R ^= f2(L, K.Km7, K.Kr7); // round 8 + L ^= f3(R, K.Km8, K.Kr8); + R ^= f1(L, K.Km9, K.Kr9); // round 10 + L ^= f2(R, K.Km10, K.Kr10); + R ^= f3(L, K.Km11, K.Kr11); // round 12 + if (K.rounds == _16_ROUNDS) + { + L ^= f1(R, K.Km12, K.Kr12); + R ^= f2(L, K.Km13, K.Kr13); // round 14 + L ^= f3(R, K.Km14, K.Kr14); + R ^= f1(L, K.Km15, K.Kr15); // round 16 + } + out[j++] = (byte)(R >>> 24); + out[j++] = (byte)(R >>> 16); + out[j++] = (byte)(R >>> 8); + out[j++] = (byte) R; + out[j++] = (byte)(L >>> 24); + out[j++] = (byte)(L >>> 16); + out[j++] = (byte)(L >>> 8); + out[j ] = (byte) L; + } + + public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + if (bs != DEFAULT_BLOCK_SIZE) + throw new IllegalArgumentException(); + Cast5Key K = (Cast5Key) k; + int L = (in[i++] & 0xFF) << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | in[i++] & 0xFF; + int R = (in[i++] & 0xFF) << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | in[i ] & 0xFF; + if (K.rounds == _16_ROUNDS) + { + L ^= f1(R, K.Km15, K.Kr15); + R ^= f3(L, K.Km14, K.Kr14); + L ^= f2(R, K.Km13, K.Kr13); + R ^= f1(L, K.Km12, K.Kr12); + } + L ^= f3(R, K.Km11, K.Kr11); + R ^= f2(L, K.Km10, K.Kr10); + L ^= f1(R, K.Km9, K.Kr9); + R ^= f3(L, K.Km8, K.Kr8); + L ^= f2(R, K.Km7, K.Kr7); + R ^= f1(L, K.Km6, K.Kr6); + L ^= f3(R, K.Km5, K.Kr5); + R ^= f2(L, K.Km4, K.Kr4); + L ^= f1(R, K.Km3, K.Kr3); + R ^= f3(L, K.Km2, K.Kr2); + L ^= f2(R, K.Km1, K.Kr1); + R ^= f1(L, K.Km0, K.Kr0); + out[j++] = (byte)(R >>> 24); + out[j++] = (byte)(R >>> 16); + out[j++] = (byte)(R >>> 8); + out[j++] = (byte) R; + out[j++] = (byte)(L >>> 24); + out[j++] = (byte)(L >>> 16); + out[j++] = (byte)(L >>> 8); + out[j ] = (byte) L; + } + + public boolean selfTest() + { + if (valid == null) + { + boolean result = super.selfTest(); // do symmetry tests + if (result) + result = testKat(KAT_KEY, KAT_CT, KAT_PT); + valid = Boolean.valueOf(result); + } + return valid.booleanValue(); + } + + private final int f1(int I, int m, int r) + { + I = m + I; + I = I << r | I >>> (32 - r); + return (((S1[(I >>> 24) & 0xFF]) + ^ S2[(I >>> 16) & 0xFF]) + - S3[(I >>> 8) & 0xFF]) + + S4[ I & 0xFF]; + } + + private final int f2(int I, int m, int r) + { + I = m ^ I; + I = I << r | I >>> (32 - r); + return (((S1[(I >>> 24) & 0xFF]) + - S2[(I >>> 16) & 0xFF]) + + S3[(I >>> 8) & 0xFF]) + ^ S4[ I & 0xFF]; + } + + private final int f3(int I, int m, int r) + { + I = m - I; + I = I << r | I >>> (32 - r); + return (((S1[(I >>> 24) & 0xFF]) + + S2[(I >>> 16) & 0xFF]) + ^ S3[(I >>> 8) & 0xFF]) + - S4[ I & 0xFF]; + } + + /** An opaque CAST5 key object. */ + private class Cast5Key + { + int rounds; + /** Masking session keys. */ + int Km0, Km1, Km2, Km3, Km4, Km5, Km6, Km7, + Km8, Km9, Km10, Km11, Km12, Km13, Km14, Km15; + /** Rotation session keys. */ + int Kr0, Kr1, Kr2, Kr3, Kr4, Kr5, Kr6, Kr7, + Kr8, Kr9, Kr10, Kr11, Kr12, Kr13, Kr14, Kr15; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/CipherFactory.java b/libjava/classpath/gnu/javax/crypto/cipher/CipherFactory.java new file mode 100644 index 000000000..fc9023626 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/CipherFactory.java @@ -0,0 +1,129 @@ +/* CipherFactory.java -- + 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.crypto.cipher; + +import gnu.java.security.Registry; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * A Factory to instantiate symmetric block cipher instances. + */ +public class CipherFactory + implements Registry +{ + /** Trivial constructor to enforce Singleton pattern. */ + private CipherFactory() + { + super(); + } + + /** + * Returns an instance of a block cipher given its name. + * + * @param name the case-insensitive name of the symmetric-key block cipher + * algorithm. + * @return an instance of the designated cipher algorithm, or + * null if none is found. + * @exception InternalError if the implementation does not pass its self-test. + */ + public static final IBlockCipher getInstance(String name) + { + if (name == null) + return null; + name = name.trim(); + IBlockCipher result = null; + if (name.equalsIgnoreCase(ANUBIS_CIPHER)) + result = new Anubis(); + else if (name.equalsIgnoreCase(BLOWFISH_CIPHER)) + result = new Blowfish(); + else if (name.equalsIgnoreCase(DES_CIPHER)) + result = new DES(); + else if (name.equalsIgnoreCase(KHAZAD_CIPHER)) + result = new Khazad(); + else if (name.equalsIgnoreCase(RIJNDAEL_CIPHER) + || name.equalsIgnoreCase(AES_CIPHER)) + result = new Rijndael(); + else if (name.equalsIgnoreCase(SERPENT_CIPHER)) + result = new Serpent(); + else if (name.equalsIgnoreCase(SQUARE_CIPHER)) + result = new Square(); + else if (name.equalsIgnoreCase(TRIPLEDES_CIPHER) + || name.equalsIgnoreCase(DESEDE_CIPHER)) + result = new TripleDES(); + else if (name.equalsIgnoreCase(TWOFISH_CIPHER)) + result = new Twofish(); + else if (name.equalsIgnoreCase(CAST5_CIPHER) + || (name.equalsIgnoreCase(CAST128_CIPHER) + || (name.equalsIgnoreCase(CAST_128_CIPHER)))) + result = new Cast5(); + else if (name.equalsIgnoreCase(NULL_CIPHER)) + result = new NullCipher(); + + if (result != null && ! result.selfTest()) + throw new InternalError(result.name()); + + return result; + } + + /** + * Returns a {@link Set} of symmetric key block cipher implementation names + * supported by this Factory. + * + * @return a {@link Set} of block cipher names (Strings). + */ + public static final Set getNames() + { + HashSet hs = new HashSet(); + hs.add(ANUBIS_CIPHER); + hs.add(BLOWFISH_CIPHER); + hs.add(DES_CIPHER); + hs.add(KHAZAD_CIPHER); + hs.add(RIJNDAEL_CIPHER); + hs.add(SERPENT_CIPHER); + hs.add(SQUARE_CIPHER); + hs.add(TRIPLEDES_CIPHER); + hs.add(TWOFISH_CIPHER); + hs.add(CAST5_CIPHER); + hs.add(NULL_CIPHER); + return Collections.unmodifiableSet(hs); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/DES.java b/libjava/classpath/gnu/javax/crypto/cipher/DES.java new file mode 100644 index 000000000..ce538b75a --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/DES.java @@ -0,0 +1,652 @@ +/* DES.java -- + Copyright (C) 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.crypto.cipher; + +import gnu.java.security.Registry; +import gnu.java.security.Properties; +import gnu.java.security.util.Util; + +import java.security.InvalidKeyException; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; + +/** + * The Data Encryption Standard. DES is a 64-bit block cipher with a 56-bit + * key, developed by IBM in the 1970's for the standardization process begun by + * the National Bureau of Standards (now NIST). + *

+ * New applications should not use DES except for compatibility. + *

+ * This version is based upon the description and sample implementation in + * [1]. + *

+ * References: + *

    + *
  1. Bruce Schneier, Applied Cryptography: Protocols, Algorithms, and + * Source Code in C, Second Edition. (1996 John Wiley and Sons) ISBN + * 0-471-11709-9. Pages 265--301, 623--632.
  2. + *
+ */ +public class DES + extends BaseCipher +{ + /** DES operates on 64 bit blocks. */ + public static final int BLOCK_SIZE = 8; + /** DES uses 56 bits of a 64 bit parity-adjusted key. */ + public static final int KEY_SIZE = 8; + // S-Boxes 1 through 8. + private static final int[] SP1 = new int[] { + 0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404, + 0x00000004, 0x00010000, 0x00000400, 0x01010400, 0x01010404, 0x00000400, + 0x01000404, 0x01010004, 0x01000000, 0x00000004, 0x00000404, 0x01000400, + 0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404, + 0x00010004, 0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404, + 0x00010404, 0x01000000, 0x00010000, 0x01010404, 0x00000004, 0x01010000, + 0x01010400, 0x01000000, 0x01000000, 0x00000400, 0x01010004, 0x00010000, + 0x00010400, 0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404, + 0x01010404, 0x00010004, 0x01010000, 0x01000404, 0x01000004, 0x00000404, + 0x00010404, 0x01010400, 0x00000404, 0x01000400, 0x01000400, 0x00000000, + 0x00010004, 0x00010400, 0x00000000, 0x01010004 }; + private static final int[] SP2 = new int[] { + 0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020, + 0x80100020, 0x80008020, 0x80000020, 0x80108020, 0x80108000, 0x80000000, + 0x80008000, 0x00100000, 0x00000020, 0x80100020, 0x00108000, 0x00100020, + 0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000, + 0x00100020, 0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000, + 0x80100000, 0x00008020, 0x00000000, 0x00108020, 0x80100020, 0x00100000, + 0x80008020, 0x80100000, 0x80108000, 0x00008000, 0x80100000, 0x80008000, + 0x00000020, 0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000, + 0x00008020, 0x80108000, 0x00100000, 0x80000020, 0x00100020, 0x80008020, + 0x80000020, 0x00100020, 0x00108000, 0x00000000, 0x80008000, 0x00008020, + 0x80000000, 0x80100020, 0x80108020, 0x00108000 }; + private static final int[] SP3 = new int[] { + 0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000, + 0x00020208, 0x08000200, 0x00020008, 0x08000008, 0x08000008, 0x00020000, + 0x08020208, 0x00020008, 0x08020000, 0x00000208, 0x08000000, 0x00000008, + 0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208, + 0x08000208, 0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208, + 0x00000200, 0x08000000, 0x08020200, 0x08000000, 0x00020008, 0x00000208, + 0x00020000, 0x08020200, 0x08000200, 0x00000000, 0x00000200, 0x00020008, + 0x08020208, 0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008, + 0x08000208, 0x00020000, 0x08000000, 0x08020208, 0x00000008, 0x00020208, + 0x00020200, 0x08000008, 0x08020000, 0x08000208, 0x00000208, 0x08020000, + 0x00020208, 0x00000008, 0x08020008, 0x00020200 }; + private static final int[] SP4 = new int[] { + 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081, + 0x00800001, 0x00002001, 0x00000000, 0x00802000, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00800080, 0x00800001, 0x00000001, 0x00002000, + 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080, + 0x00800081, 0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080, + 0x00802081, 0x00000081, 0x00800080, 0x00800001, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00000000, 0x00802000, 0x00002080, 0x00800080, + 0x00800081, 0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802081, 0x00000081, 0x00000001, 0x00002000, 0x00800001, 0x00002001, + 0x00802080, 0x00800081, 0x00002001, 0x00002080, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002000, 0x00802080 }; + private static final int[] SP5 = new int[] { + 0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100, + 0x40000000, 0x02080000, 0x40080100, 0x00080000, 0x02000100, 0x40080100, + 0x42000100, 0x42080000, 0x00080100, 0x40000000, 0x02000000, 0x40080000, + 0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100, + 0x42080000, 0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000, + 0x42000000, 0x00080100, 0x00080000, 0x42000100, 0x00000100, 0x02000000, + 0x40000000, 0x02080000, 0x42000100, 0x40080100, 0x02000100, 0x40000000, + 0x42080000, 0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000, + 0x42080100, 0x00080100, 0x42000000, 0x42080100, 0x02080000, 0x00000000, + 0x40080000, 0x42000000, 0x00080100, 0x02000100, 0x40000100, 0x00080000, + 0x00000000, 0x40080000, 0x02080100, 0x40000100 }; + private static final int[] SP6 = new int[] { + 0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010, + 0x20404010, 0x00400000, 0x20004000, 0x00404010, 0x00400000, 0x20000010, + 0x00400010, 0x20004000, 0x20000000, 0x00004010, 0x00000000, 0x00400010, + 0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010, + 0x20400010, 0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000, + 0x20404000, 0x20000000, 0x20004000, 0x00000010, 0x20400010, 0x00404000, + 0x20404010, 0x00400000, 0x00004010, 0x20000010, 0x00400000, 0x20004000, + 0x20000000, 0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000, + 0x00404010, 0x20404000, 0x00000000, 0x20400010, 0x00000010, 0x00004000, + 0x20400000, 0x00404010, 0x00004000, 0x00400010, 0x20004010, 0x00000000, + 0x20404000, 0x20000000, 0x00400010, 0x20004010 }; + private static final int[] SP7 = new int[] { + 0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802, + 0x00200802, 0x04200800, 0x04200802, 0x00200000, 0x00000000, 0x04000002, + 0x00000002, 0x04000000, 0x04200002, 0x00000802, 0x04000800, 0x00200802, + 0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002, + 0x04200000, 0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002, + 0x04000000, 0x00200800, 0x04000000, 0x00200800, 0x00200000, 0x04000802, + 0x04000802, 0x04200002, 0x04200002, 0x00000002, 0x00200002, 0x04000000, + 0x04000800, 0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800, + 0x00000802, 0x04000002, 0x04200802, 0x04200000, 0x00200800, 0x00000000, + 0x00000002, 0x04200802, 0x00000000, 0x00200802, 0x04200000, 0x00000800, + 0x04000002, 0x04000800, 0x00000800, 0x00200002 }; + private static final int[] SP8 = new int[] { + 0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040, + 0x00000040, 0x10000000, 0x00040040, 0x10040000, 0x10041040, 0x00041000, + 0x10041000, 0x00041040, 0x00001000, 0x00000040, 0x10040000, 0x10000040, + 0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000, + 0x00001040, 0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000, + 0x00041040, 0x00040000, 0x00041040, 0x00040000, 0x10041000, 0x00001000, + 0x00000040, 0x10040040, 0x00001000, 0x00041040, 0x10001000, 0x00000040, + 0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040, + 0x00000000, 0x10041040, 0x00040040, 0x10000040, 0x10040000, 0x10001000, + 0x10001040, 0x00000000, 0x10041040, 0x00041000, 0x00041000, 0x00001040, + 0x00001040, 0x00040040, 0x10000000, 0x10041000 }; + /** + * Constants that help in determining whether or not a byte array is parity + * adjusted. + */ + private static final byte[] PARITY = { + 8, 1, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 2, 8, + 0, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 3, + 0, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0, + 8, 0, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 0, 8, + 0, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0, + 8, 0, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 0, 8, + 8, 0, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 0, 8, + 0, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0, + 0, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0, + 8, 0, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 0, 8, + 8, 0, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 0, 8, + 0, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0, + 8, 0, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 0, 8, + 0, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0, + 4, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0, + 8, 5, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 6, 8 }; + // Key schedule constants. + private static final byte[] ROTARS = { + 1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28 }; + private static final byte[] PC1 = { + 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17, 9, 1, + 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 62, 54, 46, 38, + 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 60, 52, 44, 36, + 28, 20, 12, 4, 27, 19, 11, 3 }; + private static final byte[] PC2 = { + 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, 22, 18, 11, 3, + 25, 7, 15, 6, 26, 19, 12, 1, 40, 51, 30, 36, 46, 54, 29, 39, + 50, 44, 32, 47, 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 }; + /** + * Weak keys (parity adjusted): If all the bits in each half are either 0 + * or 1, then the key used for any cycle of the algorithm is the same as + * all other cycles. + */ + public static final byte[][] WEAK_KEYS = { + Util.toBytesFromString("0101010101010101"), + Util.toBytesFromString("01010101FEFEFEFE"), + Util.toBytesFromString("FEFEFEFE01010101"), + Util.toBytesFromString("FEFEFEFEFEFEFEFE") }; + /** + * Semi-weak keys (parity adjusted): Some pairs of keys encrypt plain text + * to identical cipher text. In other words, one key in the pair can decrypt + * messages that were encrypted with the other key. These keys are called + * semi-weak keys. This occurs because instead of 16 different sub-keys being + * generated, these semi-weak keys produce only two different sub-keys. + */ + public static final byte[][] SEMIWEAK_KEYS = { + Util.toBytesFromString("01FE01FE01FE01FE"), + Util.toBytesFromString("FE01FE01FE01FE01"), + Util.toBytesFromString("1FE01FE00EF10EF1"), + Util.toBytesFromString("E01FE01FF10EF10E"), + Util.toBytesFromString("01E001E001F101F1"), + Util.toBytesFromString("E001E001F101F101"), + Util.toBytesFromString("1FFE1FFE0EFE0EFE"), + Util.toBytesFromString("FE1FFE1FFE0EFE0E"), + Util.toBytesFromString("011F011F010E010E"), + Util.toBytesFromString("1F011F010E010E01"), + Util.toBytesFromString("E0FEE0FEF1FEF1FE"), + Util.toBytesFromString("FEE0FEE0FEF1FEF1") }; + /** Possible weak keys (parity adjusted) --produce 4 instead of 16 subkeys. */ + public static final byte[][] POSSIBLE_WEAK_KEYS = { + Util.toBytesFromString("1F1F01010E0E0101"), + Util.toBytesFromString("011F1F01010E0E01"), + Util.toBytesFromString("1F01011F0E01010E"), + Util.toBytesFromString("01011F1F01010E0E"), + Util.toBytesFromString("E0E00101F1F10101"), + Util.toBytesFromString("FEFE0101FEFE0101"), + Util.toBytesFromString("FEE01F01FEF10E01"), + Util.toBytesFromString("E0FE1F01F1FE0E01"), + Util.toBytesFromString("FEE0011FFEF1010E"), + Util.toBytesFromString("E0FE011FF1FE010E"), + Util.toBytesFromString("E0E01F1FF1F10E0E"), + Util.toBytesFromString("FEFE1F1FFEFE0E0E"), + Util.toBytesFromString("1F1F01010E0E0101"), + Util.toBytesFromString("011F1F01010E0E01"), + Util.toBytesFromString("1F01011F0E01010E"), + Util.toBytesFromString("01011F1F01010E0E"), + Util.toBytesFromString("01E0E00101F1F101"), + Util.toBytesFromString("1FFEE0010EFEF001"), + Util.toBytesFromString("1FE0FE010EF1FE01"), + Util.toBytesFromString("01FEFE0101FEFE01"), + Util.toBytesFromString("1FE0E01F0EF1F10E"), + Util.toBytesFromString("01FEE01F01FEF10E"), + Util.toBytesFromString("01E0FE1F01F1FE0E"), + Util.toBytesFromString("1FFEFE1F0EFEFE0E"), + + Util.toBytesFromString("E00101E0F10101F1"), + Util.toBytesFromString("FE1F01E0FE0E0EF1"), + Util.toBytesFromString("FE011FE0FE010EF1"), + Util.toBytesFromString("E01F1FE0F10E0EF1"), + Util.toBytesFromString("FE0101FEFE0101FE"), + Util.toBytesFromString("E01F01FEF10E01FE"), + Util.toBytesFromString("E0011FFEF1010EFE"), + Util.toBytesFromString("FE1F1FFEFE0E0EFE"), + Util.toBytesFromString("1FFE01E00EFE01F1"), + Util.toBytesFromString("01FE1FE001FE0EF1"), + Util.toBytesFromString("1FE001FE0EF101FE"), + Util.toBytesFromString("01E01FFE01F10EFE"), + Util.toBytesFromString("0101E0E00101F1F1"), + Util.toBytesFromString("1F1FE0E00E0EF1F1"), + Util.toBytesFromString("1F01FEE00E01FEF1"), + Util.toBytesFromString("011FFEE0010EFEF1"), + Util.toBytesFromString("1F01E0FE0E01F1FE"), + Util.toBytesFromString("011FE0FE010EF1FE"), + Util.toBytesFromString("0101FEFE0001FEFE"), + Util.toBytesFromString("1F1FFEFE0E0EFEFE"), + Util.toBytesFromString("FEFEE0E0FEFEF1F1"), + Util.toBytesFromString("E0FEFEE0F1FEFEF1"), + Util.toBytesFromString("FEE0E0FEFEF1F1FE"), + Util.toBytesFromString("E0E0FEFEF1F1FEFE") }; + + /** Default 0-argument constructor. */ + public DES() + { + super(Registry.DES_CIPHER, BLOCK_SIZE, KEY_SIZE); + } + + /** + * Adjust the parity for a raw key array. This essentially means that each + * byte in the array will have an odd number of '1' bits (the last bit in + * each byte is unused. + * + * @param kb The key array, to be parity-adjusted. + * @param offset The starting index into the key bytes. + */ + public static void adjustParity(byte[] kb, int offset) + { + for (int i = offset; i < offset + KEY_SIZE; i++) + kb[i] ^= (PARITY[kb[i] & 0xff] == 8) ? 1 : 0; + } + + /** + * Test if a byte array, which must be at least 8 bytes long, is parity + * adjusted. + * + * @param kb The key bytes. + * @param offset The starting index into the key bytes. + * @return true if the first 8 bytes of kb have been + * parity adjusted. false otherwise. + */ + public static boolean isParityAdjusted(byte[] kb, int offset) + { + int w = 0x88888888; + int n = PARITY[kb[offset + 0] & 0xff]; + n <<= 4; + n |= PARITY[kb[offset + 1] & 0xff]; + n <<= 4; + n |= PARITY[kb[offset + 2] & 0xff]; + n <<= 4; + n |= PARITY[kb[offset + 3] & 0xff]; + n <<= 4; + n |= PARITY[kb[offset + 4] & 0xff]; + n <<= 4; + n |= PARITY[kb[offset + 5] & 0xff]; + n <<= 4; + n |= PARITY[kb[offset + 6] & 0xff]; + n <<= 4; + n |= PARITY[kb[offset + 7] & 0xff]; + return (n & w) == 0; + } + + /** + * Test if a key is a weak key. + * + * @param kb The key to test. + * @return true if the key is weak. + */ + public static boolean isWeak(byte[] kb) + { + for (int i = 0; i < WEAK_KEYS.length; i++) + if (Arrays.equals(WEAK_KEYS[i], kb)) + return true; + return false; + } + + /** + * Test if a key is a semi-weak key. + * + * @param kb The key to test. + * @return true if this key is semi-weak. + */ + public static boolean isSemiWeak(byte[] kb) + { + for (int i = 0; i < SEMIWEAK_KEYS.length; i++) + if (Arrays.equals(SEMIWEAK_KEYS[i], kb)) + return true; + return false; + } + + /** + * Test if the designated byte array represents a possibly weak key. + * + * @param kb the byte array to test. + * @return true if kbrepresents a possibly weak key. + * Returns false otherwise. + */ + public static boolean isPossibleWeak(byte[] kb) + { + for (int i = 0; i < POSSIBLE_WEAK_KEYS.length; i++) + if (Arrays.equals(POSSIBLE_WEAK_KEYS[i], kb)) + return true; + return false; + } + + /** + * The core DES function. This is used for both encryption and decryption, + * the only difference being the key. + * + * @param in The input bytes. + * @param i The starting offset into the input bytes. + * @param out The output bytes. + * @param o The starting offset into the output bytes. + * @param key The working key. + */ + private static void desFunc(byte[] in, int i, byte[] out, int o, int[] key) + { + int right, left, work; + // Load. + left = (in[i++] & 0xff) << 24 + | (in[i++] & 0xff) << 16 + | (in[i++] & 0xff) << 8 + | in[i++] & 0xff; + right = (in[i++] & 0xff) << 24 + | (in[i++] & 0xff) << 16 + | (in[i++] & 0xff) << 8 + | in[i ] & 0xff; + // Initial permutation. + work = ((left >>> 4) ^ right) & 0x0F0F0F0F; + left ^= work << 4; + right ^= work; + + work = ((left >>> 16) ^ right) & 0x0000FFFF; + left ^= work << 16; + right ^= work; + + work = ((right >>> 2) ^ left) & 0x33333333; + right ^= work << 2; + left ^= work; + + work = ((right >>> 8) ^ left) & 0x00FF00FF; + right ^= work << 8; + left ^= work; + + right = ((right << 1) | ((right >>> 31) & 1)) & 0xFFFFFFFF; + work = (left ^ right) & 0xAAAAAAAA; + left ^= work; + right ^= work; + left = ((left << 1) | ((left >>> 31) & 1)) & 0xFFFFFFFF; + + int k = 0, t; + for (int round = 0; round < 8; round++) + { + work = right >>> 4 | right << 28; + work ^= key[k++]; + t = SP7[work & 0x3F]; + work >>>= 8; + t |= SP5[work & 0x3F]; + work >>>= 8; + t |= SP3[work & 0x3F]; + work >>>= 8; + t |= SP1[work & 0x3F]; + work = right ^ key[k++]; + t |= SP8[work & 0x3F]; + work >>>= 8; + t |= SP6[work & 0x3F]; + work >>>= 8; + t |= SP4[work & 0x3F]; + work >>>= 8; + t |= SP2[work & 0x3F]; + left ^= t; + + work = left >>> 4 | left << 28; + work ^= key[k++]; + t = SP7[work & 0x3F]; + work >>>= 8; + t |= SP5[work & 0x3F]; + work >>>= 8; + t |= SP3[work & 0x3F]; + work >>>= 8; + t |= SP1[work & 0x3F]; + work = left ^ key[k++]; + t |= SP8[work & 0x3F]; + work >>>= 8; + t |= SP6[work & 0x3F]; + work >>>= 8; + t |= SP4[work & 0x3F]; + work >>>= 8; + t |= SP2[work & 0x3F]; + right ^= t; + } + // The final permutation. + right = (right << 31) | (right >>> 1); + work = (left ^ right) & 0xAAAAAAAA; + left ^= work; + right ^= work; + left = (left << 31) | (left >>> 1); + + work = ((left >>> 8) ^ right) & 0x00FF00FF; + left ^= work << 8; + right ^= work; + + work = ((left >>> 2) ^ right) & 0x33333333; + left ^= work << 2; + right ^= work; + + work = ((right >>> 16) ^ left) & 0x0000FFFF; + right ^= work << 16; + left ^= work; + + work = ((right >>> 4) ^ left) & 0x0F0F0F0F; + right ^= work << 4; + left ^= work; + + out[o++] = (byte)(right >>> 24); + out[o++] = (byte)(right >>> 16); + out[o++] = (byte)(right >>> 8); + out[o++] = (byte) right; + out[o++] = (byte)(left >>> 24); + out[o++] = (byte)(left >>> 16); + out[o++] = (byte)(left >>> 8); + out[o ] = (byte) left; + } + + public Object clone() + { + return new DES(); + } + + public Iterator blockSizes() + { + return Collections.singleton(Integer.valueOf(BLOCK_SIZE)).iterator(); + } + + public Iterator keySizes() + { + return Collections.singleton(Integer.valueOf(KEY_SIZE)).iterator(); + } + + public Object makeKey(byte[] kb, int bs) throws InvalidKeyException + { + if (kb == null || kb.length != KEY_SIZE) + throw new InvalidKeyException("DES keys must be 8 bytes long"); + + if (Properties.checkForWeakKeys() + && (isWeak(kb) || isSemiWeak(kb) || isPossibleWeak(kb))) + throw new WeakKeyException(); + + int i, j, l, m, n; + long pc1m = 0, pcr = 0; + + for (i = 0; i < 56; i++) + { + l = PC1[i]; + pc1m |= ((kb[l >>> 3] & (0x80 >>> (l & 7))) != 0) ? (1L << (55 - i)) + : 0; + } + Context ctx = new Context(); + // Encryption key first. + for (i = 0; i < 16; i++) + { + pcr = 0; + m = i << 1; + n = m + 1; + for (j = 0; j < 28; j++) + { + l = j + ROTARS[i]; + if (l < 28) + pcr |= ((pc1m & 1L << (55 - l)) != 0) ? (1L << (55 - j)) : 0; + else + pcr |= ((pc1m & 1L << (55 - (l - 28))) != 0) ? (1L << (55 - j)) + : 0; + } + for (j = 28; j < 56; j++) + { + l = j + ROTARS[i]; + if (l < 56) + pcr |= ((pc1m & 1L << (55 - l)) != 0) ? (1L << (55 - j)) : 0; + else + pcr |= ((pc1m & 1L << (55 - (l - 28))) != 0) ? (1L << (55 - j)) + : 0; + } + for (j = 0; j < 24; j++) + { + if ((pcr & 1L << (55 - PC2[j])) != 0) + ctx.ek[m] |= 1 << (23 - j); + if ((pcr & 1L << (55 - PC2[j + 24])) != 0) + ctx.ek[n] |= 1 << (23 - j); + } + } + // The decryption key is the same, but in reversed order. + for (i = 0; i < Context.EXPANDED_KEY_SIZE; i += 2) + { + ctx.dk[30 - i] = ctx.ek[i]; + ctx.dk[31 - i] = ctx.ek[i + 1]; + } + // "Cook" the keys. + for (i = 0; i < 32; i += 2) + { + int x, y; + x = ctx.ek[i]; + y = ctx.ek[i + 1]; + ctx.ek[i ] = ((x & 0x00FC0000) << 6) + | ((x & 0x00000FC0) << 10) + | ((y & 0x00FC0000) >>> 10) + | ((y & 0x00000FC0) >>> 6); + ctx.ek[i + 1] = ((x & 0x0003F000) << 12) + | ((x & 0x0000003F) << 16) + | ((y & 0x0003F000) >>> 4) + | (y & 0x0000003F); + x = ctx.dk[i]; + y = ctx.dk[i + 1]; + ctx.dk[i ] = ((x & 0x00FC0000) << 6) + | ((x & 0x00000FC0) << 10) + | ((y & 0x00FC0000) >>> 10) + | ((y & 0x00000FC0) >>> 6); + ctx.dk[i + 1] = ((x & 0x0003F000) << 12) + | ((x & 0x0000003F) << 16) + | ((y & 0x0003F000) >>> 4) + | (y & 0x0000003F); + } + return ctx; + } + + public void encrypt(byte[] in, int i, byte[] out, int o, Object K, int bs) + { + desFunc(in, i, out, o, ((Context) K).ek); + } + + public void decrypt(byte[] in, int i, byte[] out, int o, Object K, int bs) + { + desFunc(in, i, out, o, ((Context) K).dk); + } + + /** + * Simple wrapper class around the session keys. Package-private so TripleDES + * can see it. + */ + final class Context + { + private static final int EXPANDED_KEY_SIZE = 32; + + /** The encryption key. */ + int[] ek; + + /** The decryption key. */ + int[] dk; + + /** Default 0-arguments constructor. */ + Context() + { + ek = new int[EXPANDED_KEY_SIZE]; + dk = new int[EXPANDED_KEY_SIZE]; + } + + byte[] getEncryptionKeyBytes() + { + return toByteArray(ek); + } + + byte[] getDecryptionKeyBytes() + { + return toByteArray(dk); + } + + byte[] toByteArray(int[] k) + { + byte[] result = new byte[4 * k.length]; + for (int i = 0, j = 0; i < k.length; i++) + { + result[j++] = (byte)(k[i] >>> 24); + result[j++] = (byte)(k[i] >>> 16); + result[j++] = (byte)(k[i] >>> 8); + result[j++] = (byte) k[i]; + } + return result; + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/IBlockCipher.java b/libjava/classpath/gnu/javax/crypto/cipher/IBlockCipher.java new file mode 100644 index 000000000..86f8b34e0 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/IBlockCipher.java @@ -0,0 +1,195 @@ +/* IBlockCipher.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.cipher; + +import java.security.InvalidKeyException; +import java.util.Iterator; +import java.util.Map; + +/** + * The basic visible methods of any symmetric key block cipher. + *

+ * A symmetric key block cipher is a function that maps n-bit plaintext blocks + * to n-bit ciphertext blocks; n being the cipher's block size. This + * encryption function is parameterised by a k-bit key, and is invertible. Its + * inverse is the decryption function. + *

+ * Possible initialisation values for an instance of this type are: + *

+ *

+ * IMPLEMENTATION NOTE: Although all the concrete classes in this + * package implement the {@link Cloneable} interface, it is important to note + * here that such an operation DOES NOT clone any session key material + * that may have been used in initialising the source cipher (the instance to be + * cloned). Instead a clone of an already initialised cipher is another instance + * that operates with the same block size but without any knowledge of + * neither key material nor key size. + */ +public interface IBlockCipher + extends Cloneable +{ + /** + * Property name of the block size in which to operate a block cipher. The + * value associated with this property name is taken to be an {@link Integer}. + */ + String CIPHER_BLOCK_SIZE = "gnu.crypto.cipher.block.size"; + /** + * Property name of the user-supplied key material. The value associated to + * this property name is taken to be a byte array. + */ + String KEY_MATERIAL = "gnu.crypto.cipher.key.material"; + + /** + * Returns the canonical name of this instance. + * + * @return the canonical name of this instance. + */ + String name(); + + /** + * Returns the default value, in bytes, of the algorithm's block size. + * + * @return the default value, in bytes, of the algorithm's block size. + */ + int defaultBlockSize(); + + /** + * Returns the default value, in bytes, of the algorithm's key size. + * + * @return the default value, in bytes, of the algorithm's key size. + */ + int defaultKeySize(); + + /** + * Returns an {@link Iterator} over the supported block sizes. Each element + * returned by this object is an {@link Integer}. + * + * @return an {@link Iterator} over the supported block sizes. + */ + Iterator blockSizes(); + + /** + * Returns an {@link Iterator} over the supported key sizes. Each element + * returned by this object is an {@link Integer}. + * + * @return an {@link Iterator} over the supported key sizes. + */ + Iterator keySizes(); + + /** + * Returns a clone of this instance. + * + * @return a clone copy of this instance. + */ + Object clone(); + + /** + * Initialises the algorithm with designated attributes. Permissible names and + * values are described in the class documentation above. + * + * @param attributes a set of name-value pairs that describes the desired + * future behaviour of this instance. + * @exception InvalidKeyException if the key data is invalid. + * @exception IllegalStateException if the instance is already initialised. + * @see #KEY_MATERIAL + * @see #CIPHER_BLOCK_SIZE + */ + void init(Map attributes) throws InvalidKeyException, IllegalStateException; + + /** + * Returns the currently set block size for this instance. + * + * @return the current block size for this instance. + * @exception IllegalStateException if the instance is not initialised. + */ + int currentBlockSize() throws IllegalStateException; + + /** + * Resets the algorithm instance for re-initialisation and use with other + * characteristics. This method always succeeds. + */ + void reset(); + + /** + * Encrypts exactly one block of plaintext. + * + * @param in the plaintext. + * @param inOffset index of in from which to start considering + * data. + * @param out the ciphertext. + * @param outOffset index of out from which to store result. + * @exception IllegalStateException if the instance is not initialised. + */ + void encryptBlock(byte[] in, int inOffset, byte[] out, int outOffset) + throws IllegalStateException; + + /** + * Decrypts exactly one block of ciphertext. + * + * @param in the plaintext. + * @param inOffset index of in from which to start considering + * data. + * @param out the ciphertext. + * @param outOffset index of out from which to store result. + * @exception IllegalStateException if the instance is not initialised. + */ + void decryptBlock(byte[] in, int inOffset, byte[] out, int outOffset) + throws IllegalStateException; + + /** + * A correctness test that consists of basic symmetric encryption / + * decryption test(s) for all supported block and key sizes, as well as one + * (1) variable key Known Answer Test (KAT). + * + * @return true if the implementation passes simple + * correctness tests. Returns false otherwise. + */ + boolean selfTest(); +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/IBlockCipherSpi.java b/libjava/classpath/gnu/javax/crypto/cipher/IBlockCipherSpi.java new file mode 100644 index 000000000..9b2172158 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/IBlockCipherSpi.java @@ -0,0 +1,124 @@ +/* IBlockCipherSpi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.cipher; + +import java.security.InvalidKeyException; +import java.util.Iterator; + +/** + * Package-private interface exposing mandatory methods to be implemented by + * concrete {@link BaseCipher} sub-classes. + */ +interface IBlockCipherSpi + extends Cloneable +{ + /** + * Returns an {@link Iterator} over the supported block sizes. Each element + * returned by this object is a {@link java.lang.Integer}. + * + * @return an Iterator over the supported block sizes. + */ + Iterator blockSizes(); + + /** + * Returns an {@link Iterator} over the supported key sizes. Each element + * returned by this object is a {@link java.lang.Integer}. + * + * @return an Iterator over the supported key sizes. + */ + Iterator keySizes(); + + /** + * Expands a user-supplied key material into a session key for a designated + * block size. + * + * @param k the user-supplied key material. + * @param bs the desired block size in bytes. + * @return an Object encapsulating the session key. + * @exception IllegalArgumentException if the block size is invalid. + * @exception InvalidKeyException if the key data is invalid. + */ + Object makeKey(byte[] k, int bs) throws InvalidKeyException; + + /** + * Encrypts exactly one block of plaintext. + * + * @param in the plaintext. + * @param inOffset index of in from which to start considering + * data. + * @param out the ciphertext. + * @param outOffset index of out from which to store the + * result. + * @param k the session key to use. + * @param bs the block size to use. + * @exception IllegalArgumentException if the block size is invalid. + * @exception ArrayIndexOutOfBoundsException if there is not enough room in + * either the plaintext or ciphertext buffers. + */ + void encrypt(byte[] in, int inOffset, byte[] out, int outOffset, Object k, + int bs); + + /** + * Decrypts exactly one block of ciphertext. + * + * @param in the ciphertext. + * @param inOffset index of in from which to start considering + * data. + * @param out the plaintext. + * @param outOffset index of out from which to store the + * result. + * @param k the session key to use. + * @param bs the block size to use. + * @exception IllegalArgumentException if the block size is invalid. + * @exception ArrayIndexOutOfBoundsException if there is not enough room in + * either the plaintext or ciphertext buffers. + */ + void decrypt(byte[] in, int inOffset, byte[] out, int outOffset, Object k, + int bs); + + /** + * A correctness test that consists of basic symmetric encryption / + * decryption test(s) for all supported block and key sizes, as well as one + * (1) variable key Known Answer Test (KAT). + * + * @return true if the implementation passes simple + * correctness tests. Returns false otherwise. + */ + boolean selfTest(); +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/Khazad.java b/libjava/classpath/gnu/javax/crypto/cipher/Khazad.java new file mode 100644 index 000000000..55e42628b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/Khazad.java @@ -0,0 +1,449 @@ +/* Khazad.java -- + 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.crypto.cipher; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.logging.Logger; + +/** + * Khazad is a 64-bit (legacy-level) block cipher that accepts a 128-bit key. + * The cipher is a uniform substitution-permutation network whose inverse only + * differs from the forward operation in the key schedule. The overall cipher + * design follows the Wide Trail strategy, favours component reuse, and permits + * a wide variety of implementation trade-offs. + *

+ * References: + *

    + *
  1. The + * Khazad Block Cipher.
    + * Paulo S.L.M. Barreto and Vincent Rijmen.
  2. + *
+ */ +public final class Khazad + extends BaseCipher +{ + private static final Logger log = Logger.getLogger(Khazad.class.getName()); + private static final int DEFAULT_BLOCK_SIZE = 8; // in bytes + private static final int DEFAULT_KEY_SIZE = 16; // in bytes + private static final int R = 8; // standard number of rounds; para. 3.7 + private static final String Sd = // p. 20 [KHAZAD] + "\uBA54\u2F74\u53D3\uD24D\u50AC\u8DBF\u7052\u9A4C" + + "\uEAD5\u97D1\u3351\u5BA6\uDE48\uA899\uDB32\uB7FC" + + "\uE39E\u919B\uE2BB\u416E\uA5CB\u6B95\uA1F3\uB102" + + "\uCCC4\u1D14\uC363\uDA5D\u5FDC\u7DCD\u7F5A\u6C5C" + + "\uF726\uFFED\uE89D\u6F8E\u19A0\uF089\u0F07\uAFFB" + + "\u0815\u0D04\u0164\uDF76\u79DD\u3D16\u3F37\u6D38" + + "\uB973\uE935\u5571\u7B8C\u7288\uF62A\u3E5E\u2746" + + "\u0C65\u6861\u03C1\u57D6\uD958\uD866\uD73A\uC83C" + + "\uFA96\uA798\uECB8\uC7AE\u694B\uABA9\u670A\u47F2" + + "\uB522\uE5EE\uBE2B\u8112\u831B\u0E23\uF545\u21CE" + + "\u492C\uF9E6\uB628\u1782\u1A8B\uFE8A\u09C9\u874E" + + "\uE12E\uE4E0\uEB90\uA41E\u8560\u0025\uF4F1\u940B" + + "\uE775\uEF34\u31D4\uD086\u7EAD\uFD29\u303B\u9FF8" + + "\uC613\u0605\uC511\u777C\u7A78\u361C\u3959\u1856" + + "\uB3B0\u2420\uB292\uA3C0\u4462\u10B4\u8443\u93C2" + + "\u4ABD\u8F2D\uBC9C\u6A40\uCFA2\u804F\u1FCA\uAA42"; + private static final byte[] S = new byte[256]; + private static final int[] T0 = new int[256]; + private static final int[] T1 = new int[256]; + private static final int[] T2 = new int[256]; + private static final int[] T3 = new int[256]; + private static final int[] T4 = new int[256]; + private static final int[] T5 = new int[256]; + private static final int[] T6 = new int[256]; + private static final int[] T7 = new int[256]; + private static final int[][] rc = new int[R + 1][2]; // round constants + /** + * KAT vector (from ecb_vk): I=120 KEY=00000000000000000000000000000100 + * CT=A0C86A1BBE2CBF4C + */ + private static final byte[] KAT_KEY = + Util.toBytesFromString("00000000000000000000000000000100"); + private static final byte[] KAT_CT = Util.toBytesFromString("A0C86A1BBE2CBF4C"); + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + static + { + long time = System.currentTimeMillis(); + long ROOT = 0x11d; // para. 2.1 [KHAZAD] + int i, j; + int s, s2, s3, s4, s5, s6, s7, s8, sb; + char c; + for (i = 0; i < 256; i++) + { + c = Sd.charAt(i >>> 1); + s = ((i & 1) == 0 ? c >>> 8 : c) & 0xFF; + S[i] = (byte) s; + s2 = s << 1; + if (s2 > 0xFF) + s2 ^= ROOT; + s3 = s2 ^ s; + s4 = s2 << 1; + if (s4 > 0xFF) + s4 ^= ROOT; + s5 = s4 ^ s; + s6 = s4 ^ s2; + s7 = s6 ^ s; + s8 = s4 << 1; + if (s8 > 0xFF) + s8 ^= ROOT; + sb = s8 ^ s2 ^ s; + T0[i] = s << 24 | s3 << 16 | s4 << 8 | s5; + T1[i] = s3 << 24 | s << 16 | s5 << 8 | s4; + T2[i] = s4 << 24 | s5 << 16 | s << 8 | s3; + T3[i] = s5 << 24 | s4 << 16 | s3 << 8 | s; + T4[i] = s6 << 24 | s8 << 16 | sb << 8 | s7; + T5[i] = s8 << 24 | s6 << 16 | s7 << 8 | sb; + T6[i] = sb << 24 | s7 << 16 | s6 << 8 | s8; + T7[i] = s7 << 24 | sb << 16 | s8 << 8 | s6; + } + for (i = 0, j = 0; i < R + 1; i++) // compute round constant + { + rc[i][0] = S[j++] << 24 + | (S[j++] & 0xFF) << 16 + | (S[j++] & 0xFF) << 8 + | (S[j++] & 0xFF); + rc[i][1] = S[j++] << 24 + | (S[j++] & 0xFF) << 16 + | (S[j++] & 0xFF) << 8 + | (S[j++] & 0xFF); + } + time = System.currentTimeMillis() - time; + if (Configuration.DEBUG) + { + log.fine("Static data"); + log.fine("T0[]:"); + StringBuilder b; + for (i = 0; i < 64; i++) + { + b = new StringBuilder(); + for (j = 0; j < 4; j++) + b.append("0x").append(Util.toString(T0[i * 4 + j])).append(", "); + log.fine(b.toString()); + } + log.fine("T1[]:"); + for (i = 0; i < 64; i++) + { + b = new StringBuilder(); + for (j = 0; j < 4; j++) + b.append("0x").append(Util.toString(T1[i * 4 + j])).append(", "); + log.fine(b.toString()); + } + log.fine("T2[]:"); + for (i = 0; i < 64; i++) + { + b = new StringBuilder(); + for (j = 0; j < 4; j++) + b.append("0x").append(Util.toString(T2[i * 4 + j])).append(", "); + log.fine(b.toString()); + } + log.fine("T3[]:"); + for (i = 0; i < 64; i++) + { + b = new StringBuilder(); + for (j = 0; j < 4; j++) + b.append("0x").append(Util.toString(T3[i * 4 + j])).append(", "); + log.fine(b.toString()); + } + log.fine("T4[]:"); + for (i = 0; i < 64; i++) + { + b = new StringBuilder(); + for (j = 0; j < 4; j++) + b.append("0x").append(Util.toString(T4[i * 4 + j])).append(", "); + log.fine(b.toString()); + } + log.fine("T5[]:"); + for (i = 0; i < 64; i++) + { + b = new StringBuilder(); + for (j = 0; j < 4; j++) + b.append("0x").append(Util.toString(T5[i * 4 + j])).append(", "); + log.fine(b.toString()); + } + log.fine("T6[]:"); + for (i = 0; i < 64; i++) + { + b = new StringBuilder(); + for (j = 0; j < 4; j++) + b.append("0x").append(Util.toString(T6[i * 4 + j])).append(", "); + log.fine(b.toString()); + } + log.fine("T7[]:"); + for (i = 0; i < 64; i++) + { + b = new StringBuilder(); + for (j = 0; j < 4; j++) + b.append("0x").append(Util.toString(T7[i * 4 + j])).append(", "); + log.fine(b.toString()); + } + log.fine("rc[]:"); + for (i = 0; i < R + 1; i++) + log.fine("0x" + Util.toString(rc[i][0]) + Util.toString(rc[i][1])); + log.fine("Total initialization time: " + time + " ms."); + } + } + + /** Trivial 0-arguments constructor. */ + public Khazad() + { + super(Registry.KHAZAD_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + private static void khazad(byte[] in, int i, byte[] out, int j, int[][] K) + { + // sigma(K[0]) + int k0 = K[0][0]; + int k1 = K[0][1]; + int a0 = (in[i++] << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) ) ^ k0; + int a1 = (in[i++] << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i ] & 0xFF) ) ^ k1; + int b0, b1; + // round function + for (int r = 1; r < R; r++) + { + k0 = K[r][0]; + k1 = K[r][1]; + b0 = T0[ a0 >>> 24 ] + ^ T1[(a0 >>> 16) & 0xFF] + ^ T2[(a0 >>> 8) & 0xFF] + ^ T3[ a0 & 0xFF] + ^ T4[ a1 >>> 24 ] + ^ T5[(a1 >>> 16) & 0xFF] + ^ T6[(a1 >>> 8) & 0xFF] + ^ T7[ a1 & 0xFF] ^ k0; + b1 = T0[ a1 >>> 24 ] + ^ T1[(a1 >>> 16) & 0xFF] + ^ T2[(a1 >>> 8) & 0xFF] + ^ T3[ a1 & 0xFF] + ^ T4[ a0 >>> 24 ] + ^ T5[(a0 >>> 16) & 0xFF] + ^ T6[(a0 >>> 8) & 0xFF] + ^ T7[ a0 & 0xFF] ^ k1; + a0 = b0; + a1 = b1; + if (Configuration.DEBUG) + log.fine("T" + r + "=" + Util.toString(a0) + Util.toString(a1)); + } + // sigma(K[R]) o gamma applied to previous output + k0 = K[R][0]; + k1 = K[R][1]; + out[j++] = (byte)(S[ a0 >>> 24 ] ^ (k0 >>> 24)); + out[j++] = (byte)(S[(a0 >>> 16) & 0xFF] ^ (k0 >>> 16)); + out[j++] = (byte)(S[(a0 >>> 8) & 0xFF] ^ (k0 >>> 8)); + out[j++] = (byte)(S[ a0 & 0xFF] ^ k0 ); + out[j++] = (byte)(S[ a1 >>> 24 ] ^ (k1 >>> 24)); + out[j++] = (byte)(S[(a1 >>> 16) & 0xFF] ^ (k1 >>> 16)); + out[j++] = (byte)(S[(a1 >>> 8) & 0xFF] ^ (k1 >>> 8)); + out[j ] = (byte)(S[ a1 & 0xFF] ^ k1 ); + if (Configuration.DEBUG) + log.fine("T=" + Util.toString(out, j - 7, 8) + "\n"); + } + + public Object clone() + { + Khazad result = new Khazad(); + result.currentBlockSize = this.currentBlockSize; + + return result; + } + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(DEFAULT_BLOCK_SIZE)); + + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(DEFAULT_KEY_SIZE)); + return Collections.unmodifiableList(al).iterator(); + } + + /** + * Expands a user-supplied key material into a session key for a designated + * block size. + * + * @param uk the 128-bit user-supplied key material. + * @param bs the desired block size in bytes. + * @return an Object encapsulating the session key. + * @exception IllegalArgumentException if the block size is not 16 (128-bit). + * @exception InvalidKeyException if the key data is invalid. + */ + public Object makeKey(byte[] uk, int bs) throws InvalidKeyException + { + if (bs != DEFAULT_BLOCK_SIZE) + throw new IllegalArgumentException(); + if (uk == null) + throw new InvalidKeyException("Empty key"); + if (uk.length != 16) + throw new InvalidKeyException("Key is not 128-bit."); + int[][] Ke = new int[R + 1][2]; // encryption round keys + int[][] Kd = new int[R + 1][2]; // decryption round keys + int r, i; + int k20, k21, k10, k11, rc0, rc1, kr0, kr1; + i = 0; + k20 = uk[i++] << 24 + | (uk[i++] & 0xFF) << 16 + | (uk[i++] & 0xFF) << 8 + | (uk[i++] & 0xFF); + k21 = uk[i++] << 24 + | (uk[i++] & 0xFF) << 16 + | (uk[i++] & 0xFF) << 8 + | (uk[i++] & 0xFF); + k10 = uk[i++] << 24 + | (uk[i++] & 0xFF) << 16 + | (uk[i++] & 0xFF) << 8 + | (uk[i++] & 0xFF); + k11 = uk[i++] << 24 + | (uk[i++] & 0xFF) << 16 + | (uk[i++] & 0xFF) << 8 + | (uk[i++] & 0xFF); + for (r = 0, i = 0; r <= R; r++) + { + rc0 = rc[r][0]; + rc1 = rc[r][1]; + kr0 = T0[ k10 >>> 24 ] + ^ T1[(k10 >>> 16) & 0xFF] + ^ T2[(k10 >>> 8) & 0xFF] + ^ T3[ k10 & 0xFF] + ^ T4[(k11 >>> 24) & 0xFF] + ^ T5[(k11 >>> 16) & 0xFF] + ^ T6[(k11 >>> 8) & 0xFF] + ^ T7[ k11 & 0xFF] ^ rc0 ^ k20; + kr1 = T0[ k11 >>> 24 ] + ^ T1[(k11 >>> 16) & 0xFF] + ^ T2[(k11 >>> 8) & 0xFF] + ^ T3[ k11 & 0xFF] + ^ T4[(k10 >>> 24) & 0xFF] + ^ T5[(k10 >>> 16) & 0xFF] + ^ T6[(k10 >>> 8) & 0xFF] + ^ T7[ k10 & 0xFF] ^ rc1 ^ k21; + Ke[r][0] = kr0; + Ke[r][1] = kr1; + k20 = k10; + k21 = k11; + k10 = kr0; + k11 = kr1; + if (r == 0 || r == R) + { + Kd[R - r][0] = kr0; + Kd[R - r][1] = kr1; + } + else + { + Kd[R - r][0] = T0[S[ kr0 >>> 24 ] & 0xFF] + ^ T1[S[(kr0 >>> 16) & 0xFF] & 0xFF] + ^ T2[S[(kr0 >>> 8) & 0xFF] & 0xFF] + ^ T3[S[ kr0 & 0xFF] & 0xFF] + ^ T4[S[ kr1 >>> 24 ] & 0xFF] + ^ T5[S[(kr1 >>> 16) & 0xFF] & 0xFF] + ^ T6[S[(kr1 >>> 8) & 0xFF] & 0xFF] + ^ T7[S[ kr1 & 0xFF] & 0xFF]; + Kd[R - r][1] = T0[S[ kr1 >>> 24 ] & 0xFF] + ^ T1[S[(kr1 >>> 16) & 0xFF] & 0xFF] + ^ T2[S[(kr1 >>> 8) & 0xFF] & 0xFF] + ^ T3[S[ kr1 & 0xFF] & 0xFF] + ^ T4[S[ kr0 >>> 24 ] & 0xFF] + ^ T5[S[(kr0 >>> 16) & 0xFF] & 0xFF] + ^ T6[S[(kr0 >>> 8) & 0xFF] & 0xFF] + ^ T7[S[ kr0 & 0xFF] & 0xFF]; + } + } + if (Configuration.DEBUG) + { + log.fine("Key schedule"); + log.fine("Ke[]:"); + for (r = 0; r < R + 1; r++) + log.fine("#" + r + ": 0x" + Util.toString(Ke[r][0]) + + Util.toString(Ke[r][1])); + log.fine("Kd[]:"); + for (r = 0; r < R + 1; r++) + log.fine("#" + r + ": 0x" + Util.toString(Kd[r][0]) + + Util.toString(Kd[r][1])); + } + return new Object[] { Ke, Kd }; + } + + public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + if (bs != DEFAULT_BLOCK_SIZE) + throw new IllegalArgumentException(); + int[][] K = (int[][])((Object[]) k)[0]; + khazad(in, i, out, j, K); + } + + public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + if (bs != DEFAULT_BLOCK_SIZE) + throw new IllegalArgumentException(); + int[][] K = (int[][])((Object[]) k)[1]; + khazad(in, i, out, j, K); + } + + public boolean selfTest() + { + if (valid == null) + { + boolean result = super.selfTest(); // do symmetry tests + if (result) + result = testKat(KAT_KEY, KAT_CT); + valid = Boolean.valueOf(result); + } + return valid.booleanValue(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/NullCipher.java b/libjava/classpath/gnu/javax/crypto/cipher/NullCipher.java new file mode 100644 index 000000000..f23ea489f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/NullCipher.java @@ -0,0 +1,108 @@ +/* NullCipher.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.cipher; + +import gnu.java.security.Registry; + +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; + +/** + * The implementation of a Null block cipher. + *

+ * This cipher does not alter its input at all, claims to process block sizes + * 128-, 192- and 256-bit long, and key sizes from 64- to 512-bit in 8-bit + * increments. + */ +public final class NullCipher + extends BaseCipher +{ + /** Trivial 0-arguments constructor. */ + public NullCipher() + { + super(Registry.NULL_CIPHER, 16, 16); + } + + public Object clone() + { + NullCipher result = new NullCipher(); + result.currentBlockSize = this.currentBlockSize; + return result; + } + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(64 / 8)); + al.add(Integer.valueOf(128 / 8)); + al.add(Integer.valueOf(192 / 8)); + al.add(Integer.valueOf(256 / 8)); + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + for (int n = 8; n < 64; n++) + al.add(Integer.valueOf(n)); + return Collections.unmodifiableList(al).iterator(); + } + + public Object makeKey(byte[] uk, int bs) throws InvalidKeyException + { + return new Object(); + } + + public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + System.arraycopy(in, i, out, j, bs); + } + + public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + System.arraycopy(in, i, out, j, bs); + } + + public boolean selfTest() + { + return true; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/Rijndael.java b/libjava/classpath/gnu/javax/crypto/cipher/Rijndael.java new file mode 100644 index 000000000..0463fe51d --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/Rijndael.java @@ -0,0 +1,704 @@ +/* Rijndael.java -- + 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.crypto.cipher; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.logging.Logger; + +/** + * Rijndael --pronounced Reindaal-- is the AES. It is a variable block-size + * (128-, 192- and 256-bit), variable key-size (128-, 192- and 256-bit) + * symmetric key block cipher. + *

+ * References: + *

    + *
  1. The Rijndael + * Block Cipher - AES Proposal.
    + * Vincent Rijmen and + * Joan Daemen.
  2. + *
+ */ +public final class Rijndael + extends BaseCipher +{ + private static final Logger log = Logger.getLogger(Rijndael.class.getName()); + private static final int DEFAULT_BLOCK_SIZE = 16; // in bytes + private static final int DEFAULT_KEY_SIZE = 16; // in bytes + private static final String SS = + "\u637C\u777B\uF26B\u6FC5\u3001\u672B\uFED7\uAB76" + + "\uCA82\uC97D\uFA59\u47F0\uADD4\uA2AF\u9CA4\u72C0" + + "\uB7FD\u9326\u363F\uF7CC\u34A5\uE5F1\u71D8\u3115" + + "\u04C7\u23C3\u1896\u059A\u0712\u80E2\uEB27\uB275" + + "\u0983\u2C1A\u1B6E\u5AA0\u523B\uD6B3\u29E3\u2F84" + + "\u53D1\u00ED\u20FC\uB15B\u6ACB\uBE39\u4A4C\u58CF" + + "\uD0EF\uAAFB\u434D\u3385\u45F9\u027F\u503C\u9FA8" + + "\u51A3\u408F\u929D\u38F5\uBCB6\uDA21\u10FF\uF3D2" + + "\uCD0C\u13EC\u5F97\u4417\uC4A7\u7E3D\u645D\u1973" + + "\u6081\u4FDC\u222A\u9088\u46EE\uB814\uDE5E\u0BDB" + + "\uE032\u3A0A\u4906\u245C\uC2D3\uAC62\u9195\uE479" + + "\uE7C8\u376D\u8DD5\u4EA9\u6C56\uF4EA\u657A\uAE08" + + "\uBA78\u252E\u1CA6\uB4C6\uE8DD\u741F\u4BBD\u8B8A" + + "\u703E\uB566\u4803\uF60E\u6135\u57B9\u86C1\u1D9E" + + "\uE1F8\u9811\u69D9\u8E94\u9B1E\u87E9\uCE55\u28DF" + + "\u8CA1\u890D\uBFE6\u4268\u4199\u2D0F\uB054\uBB16"; + private static final byte[] S = new byte[256]; + private static final byte[] Si = new byte[256]; + private static final int[] T1 = new int[256]; + private static final int[] T2 = new int[256]; + private static final int[] T3 = new int[256]; + private static final int[] T4 = new int[256]; + private static final int[] T5 = new int[256]; + private static final int[] T6 = new int[256]; + private static final int[] T7 = new int[256]; + private static final int[] T8 = new int[256]; + private static final int[] U1 = new int[256]; + private static final int[] U2 = new int[256]; + private static final int[] U3 = new int[256]; + private static final int[] U4 = new int[256]; + private static final byte[] rcon = new byte[30]; + private static final int[][][] shifts = new int[][][] { + { { 0, 0 }, { 1, 3 }, { 2, 2 }, { 3, 1 } }, + { { 0, 0 }, { 1, 5 }, { 2, 4 }, { 3, 3 } }, + { { 0, 0 }, { 1, 7 }, { 3, 5 }, { 4, 4 } } }; + /** + * KAT vector (from ecb_vk): I=96 + * KEY=0000000000000000000000010000000000000000000000000000000000000000 + * CT=E44429474D6FC3084EB2A6B8B46AF754 + */ + private static final byte[] KAT_KEY = Util.toBytesFromString( + "0000000000000000000000010000000000000000000000000000000000000000"); + private static final byte[] KAT_CT = Util.toBytesFromString( + "E44429474D6FC3084EB2A6B8B46AF754"); + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + static + { + long time = System.currentTimeMillis(); + int ROOT = 0x11B; + int i, j = 0; + // S-box, inverse S-box, T-boxes, U-boxes + int s, s2, s3, i2, i4, i8, i9, ib, id, ie, t; + char c; + for (i = 0; i < 256; i++) + { + c = SS.charAt(i >>> 1); + S[i] = (byte)(((i & 1) == 0) ? c >>> 8 : c & 0xFF); + s = S[i] & 0xFF; + Si[s] = (byte) i; + s2 = s << 1; + if (s2 >= 0x100) + s2 ^= ROOT; + s3 = s2 ^ s; + i2 = i << 1; + if (i2 >= 0x100) + i2 ^= ROOT; + i4 = i2 << 1; + if (i4 >= 0x100) + i4 ^= ROOT; + i8 = i4 << 1; + if (i8 >= 0x100) + i8 ^= ROOT; + i9 = i8 ^ i; + ib = i9 ^ i2; + id = i9 ^ i4; + ie = i8 ^ i4 ^ i2; + T1[i] = t = (s2 << 24) | (s << 16) | (s << 8) | s3; + T2[i] = (t >>> 8) | (t << 24); + T3[i] = (t >>> 16) | (t << 16); + T4[i] = (t >>> 24) | (t << 8); + T5[s] = U1[i] = t = (ie << 24) | (i9 << 16) | (id << 8) | ib; + T6[s] = U2[i] = (t >>> 8) | (t << 24); + T7[s] = U3[i] = (t >>> 16) | (t << 16); + T8[s] = U4[i] = (t >>> 24) | (t << 8); + } + // round constants + int r = 1; + rcon[0] = 1; + for (i = 1; i < 30; i++) + { + r <<= 1; + if (r >= 0x100) + r ^= ROOT; + rcon[i] = (byte) r; + } + time = System.currentTimeMillis() - time; + if (Configuration.DEBUG) + { + log.fine("Static Data"); + log.fine("S[]:"); + StringBuilder sb; + for (i = 0; i < 16; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 16; j++) + sb.append("0x").append(Util.toString(S[i * 16 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("Si[]:"); + for (i = 0; i < 16; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 16; j++) + sb.append("0x").append(Util.toString(Si[i * 16 + j])).append(", "); + log.fine(sb.toString()); + } + + log.fine("T1[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T1[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("T2[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T2[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("T3[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T3[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("T4[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T4[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("T5[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T5[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("T6[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T6[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("T7[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T7[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("T8[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T8[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + + log.fine("U1[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(U1[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("U2[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(U2[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("U3[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(U3[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("U4[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(U4[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + + log.fine("rcon[]:"); + for (i = 0; i < 5; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 6; j++) + sb.append("0x").append(Util.toString(rcon[i * 6 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("Total initialization time: " + time + " ms."); + } + } + + /** Trivial 0-arguments constructor. */ + public Rijndael() + { + super(Registry.RIJNDAEL_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + /** + * Returns the number of rounds for a given Rijndael's key and block sizes. + * + * @param ks the size of the user key material in bytes. + * @param bs the desired block size in bytes. + * @return the number of rounds for a given Rijndael's key and block sizes. + */ + public static int getRounds(int ks, int bs) + { + switch (ks) + { + case 16: + return bs == 16 ? 10 : (bs == 24 ? 12 : 14); + case 24: + return bs != 32 ? 12 : 14; + default: // 32 bytes = 256 bits + return 14; + } + } + + private static void rijndaelEncrypt(byte[] in, int inOffset, byte[] out, + int outOffset, Object sessionKey, int bs) + { + Object[] sKey = (Object[]) sessionKey; // extract encryption round keys + int[][] Ke = (int[][]) sKey[0]; + int BC = bs / 4; + int ROUNDS = Ke.length - 1; + int SC = BC == 4 ? 0 : (BC == 6 ? 1 : 2); + int s1 = shifts[SC][1][0]; + int s2 = shifts[SC][2][0]; + int s3 = shifts[SC][3][0]; + int[] a = new int[BC]; + int[] t = new int[BC]; // temporary work array + int i, tt; + for (i = 0; i < BC; i++) // plaintext to ints + key + t[i] = (in[inOffset++] << 24 + | (in[inOffset++] & 0xFF) << 16 + | (in[inOffset++] & 0xFF) << 8 + | (in[inOffset++] & 0xFF) ) ^ Ke[0][i]; + for (int r = 1; r < ROUNDS; r++) // apply round transforms + { + for (i = 0; i < BC; i++) + a[i] = (T1[(t[ i ] >>> 24) ] + ^ T2[(t[(i + s1) % BC] >>> 16) & 0xFF] + ^ T3[(t[(i + s2) % BC] >>> 8) & 0xFF] + ^ T4[ t[(i + s3) % BC] & 0xFF]) ^ Ke[r][i]; + System.arraycopy(a, 0, t, 0, BC); + if (Configuration.DEBUG) + log.fine("CT" + r + "=" + Util.toString(t)); + } + for (i = 0; i < BC; i++) // last round is special + { + tt = Ke[ROUNDS][i]; + out[outOffset++] = (byte)(S[(t[ i ] >>> 24) ] ^ (tt >>> 24)); + out[outOffset++] = (byte)(S[(t[(i + s1) % BC] >>> 16) & 0xFF] ^ (tt >>> 16)); + out[outOffset++] = (byte)(S[(t[(i + s2) % BC] >>> 8) & 0xFF] ^ (tt >>> 8)); + out[outOffset++] = (byte)(S[ t[(i + s3) % BC] & 0xFF] ^ tt ); + } + if (Configuration.DEBUG) + log.fine("CT=" + Util.toString(out, outOffset - bs, bs)); + } + + private static void rijndaelDecrypt(byte[] in, int inOffset, byte[] out, + int outOffset, Object sessionKey, int bs) + { + Object[] sKey = (Object[]) sessionKey; // extract decryption round keys + int[][] Kd = (int[][]) sKey[1]; + int BC = bs / 4; + int ROUNDS = Kd.length - 1; + int SC = BC == 4 ? 0 : (BC == 6 ? 1 : 2); + int s1 = shifts[SC][1][1]; + int s2 = shifts[SC][2][1]; + int s3 = shifts[SC][3][1]; + int[] a = new int[BC]; + int[] t = new int[BC]; // temporary work array + int i, tt; + for (i = 0; i < BC; i++) // ciphertext to ints + key + t[i] = (in[inOffset++] << 24 + | (in[inOffset++] & 0xFF) << 16 + | (in[inOffset++] & 0xFF) << 8 + | (in[inOffset++] & 0xFF) ) ^ Kd[0][i]; + for (int r = 1; r < ROUNDS; r++) // apply round transforms + { + for (i = 0; i < BC; i++) + a[i] = (T5[(t[ i ] >>> 24) ] + ^ T6[(t[(i + s1) % BC] >>> 16) & 0xFF] + ^ T7[(t[(i + s2) % BC] >>> 8) & 0xFF] + ^ T8[ t[(i + s3) % BC] & 0xFF]) ^ Kd[r][i]; + System.arraycopy(a, 0, t, 0, BC); + if (Configuration.DEBUG) + log.fine("PT" + r + "=" + Util.toString(t)); + } + for (i = 0; i < BC; i++) // last round is special + { + tt = Kd[ROUNDS][i]; + out[outOffset++] = (byte)(Si[(t[ i ] >>> 24) ] ^ (tt >>> 24)); + out[outOffset++] = (byte)(Si[(t[(i + s1) % BC] >>> 16) & 0xFF] ^ (tt >>> 16)); + out[outOffset++] = (byte)(Si[(t[(i + s2) % BC] >>> 8) & 0xFF] ^ (tt >>> 8)); + out[outOffset++] = (byte)(Si[ t[(i + s3) % BC] & 0xFF] ^ tt ); + } + if (Configuration.DEBUG) + log.fine("PT=" + Util.toString(out, outOffset - bs, bs)); + } + + private static void aesEncrypt(byte[] in, int i, byte[] out, int j, Object key) + { + int[][] Ke = (int[][])((Object[]) key)[0]; // extract encryption round keys + int ROUNDS = Ke.length - 1; + int[] Ker = Ke[0]; + // plaintext to ints + key + int t0 = (in[i++] << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) ) ^ Ker[0]; + int t1 = (in[i++] << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) ) ^ Ker[1]; + int t2 = (in[i++] << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) ) ^ Ker[2]; + int t3 = (in[i++] << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) ) ^ Ker[3]; + int a0, a1, a2, a3; + for (int r = 1; r < ROUNDS; r++) // apply round transforms + { + Ker = Ke[r]; + a0 = (T1[(t0 >>> 24) ] + ^ T2[(t1 >>> 16) & 0xFF] + ^ T3[(t2 >>> 8) & 0xFF] + ^ T4[ t3 & 0xFF]) ^ Ker[0]; + a1 = (T1[(t1 >>> 24) ] + ^ T2[(t2 >>> 16) & 0xFF] + ^ T3[(t3 >>> 8) & 0xFF] + ^ T4[ t0 & 0xFF]) ^ Ker[1]; + a2 = (T1[(t2 >>> 24) ] + ^ T2[(t3 >>> 16) & 0xFF] + ^ T3[(t0 >>> 8) & 0xFF] + ^ T4[ t1 & 0xFF]) ^ Ker[2]; + a3 = (T1[(t3 >>> 24) ] + ^ T2[(t0 >>> 16) & 0xFF] + ^ T3[(t1 >>> 8) & 0xFF] + ^ T4[ t2 & 0xFF]) ^ Ker[3]; + t0 = a0; + t1 = a1; + t2 = a2; + t3 = a3; + if (Configuration.DEBUG) + log.fine("CT" + r + "=" + Util.toString(t0) + Util.toString(t1) + + Util.toString(t2) + Util.toString(t3)); + } + // last round is special + Ker = Ke[ROUNDS]; + int tt = Ker[0]; + out[j++] = (byte)(S[(t0 >>> 24) ] ^ (tt >>> 24)); + out[j++] = (byte)(S[(t1 >>> 16) & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte)(S[(t2 >>> 8) & 0xFF] ^ (tt >>> 8)); + out[j++] = (byte)(S[ t3 & 0xFF] ^ tt ); + tt = Ker[1]; + out[j++] = (byte)(S[(t1 >>> 24) ] ^ (tt >>> 24)); + out[j++] = (byte)(S[(t2 >>> 16) & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte)(S[(t3 >>> 8) & 0xFF] ^ (tt >>> 8)); + out[j++] = (byte)(S[ t0 & 0xFF] ^ tt ); + tt = Ker[2]; + out[j++] = (byte)(S[(t2 >>> 24) ] ^ (tt >>> 24)); + out[j++] = (byte)(S[(t3 >>> 16) & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte)(S[(t0 >>> 8) & 0xFF] ^ (tt >>> 8)); + out[j++] = (byte)(S[ t1 & 0xFF] ^ tt ); + tt = Ker[3]; + out[j++] = (byte)(S[(t3 >>> 24) ] ^ (tt >>> 24)); + out[j++] = (byte)(S[(t0 >>> 16) & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte)(S[(t1 >>> 8) & 0xFF] ^ (tt >>> 8)); + out[j++] = (byte)(S[ t2 & 0xFF] ^ tt ); + if (Configuration.DEBUG) + log.fine("CT=" + Util.toString(out, j - 16, 16)); + } + + private static void aesDecrypt(byte[] in, int i, byte[] out, int j, Object key) + { + int[][] Kd = (int[][])((Object[]) key)[1]; // extract decryption round keys + int ROUNDS = Kd.length - 1; + int[] Kdr = Kd[0]; + // ciphertext to ints + key + int t0 = (in[i++] << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) ) ^ Kdr[0]; + int t1 = (in[i++] << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) ) ^ Kdr[1]; + int t2 = (in[i++] << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) ) ^ Kdr[2]; + int t3 = (in[i++] << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) ) ^ Kdr[3]; + + int a0, a1, a2, a3; + for (int r = 1; r < ROUNDS; r++) // apply round transforms + { + Kdr = Kd[r]; + a0 = (T5[(t0 >>> 24) ] + ^ T6[(t3 >>> 16) & 0xFF] + ^ T7[(t2 >>> 8) & 0xFF] + ^ T8[ t1 & 0xFF]) ^ Kdr[0]; + a1 = (T5[(t1 >>> 24) ] + ^ T6[(t0 >>> 16) & 0xFF] + ^ T7[(t3 >>> 8) & 0xFF] + ^ T8[ t2 & 0xFF]) ^ Kdr[1]; + a2 = (T5[(t2 >>> 24) ] + ^ T6[(t1 >>> 16) & 0xFF] + ^ T7[(t0 >>> 8) & 0xFF] + ^ T8[ t3 & 0xFF]) ^ Kdr[2]; + a3 = (T5[(t3 >>> 24) ] + ^ T6[(t2 >>> 16) & 0xFF] + ^ T7[(t1 >>> 8) & 0xFF] + ^ T8[ t0 & 0xFF]) ^ Kdr[3]; + t0 = a0; + t1 = a1; + t2 = a2; + t3 = a3; + if (Configuration.DEBUG) + log.fine("PT" + r + "=" + Util.toString(t0) + Util.toString(t1) + + Util.toString(t2) + Util.toString(t3)); + } + // last round is special + Kdr = Kd[ROUNDS]; + int tt = Kdr[0]; + out[j++] = (byte)(Si[(t0 >>> 24) ] ^ (tt >>> 24)); + out[j++] = (byte)(Si[(t3 >>> 16) & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte)(Si[(t2 >>> 8) & 0xFF] ^ (tt >>> 8)); + out[j++] = (byte)(Si[ t1 & 0xFF] ^ tt ); + tt = Kdr[1]; + out[j++] = (byte)(Si[(t1 >>> 24) ] ^ (tt >>> 24)); + out[j++] = (byte)(Si[(t0 >>> 16) & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte)(Si[(t3 >>> 8) & 0xFF] ^ (tt >>> 8)); + out[j++] = (byte)(Si[ t2 & 0xFF] ^ tt ); + tt = Kdr[2]; + out[j++] = (byte)(Si[(t2 >>> 24) ] ^ (tt >>> 24)); + out[j++] = (byte)(Si[(t1 >>> 16) & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte)(Si[(t0 >>> 8) & 0xFF] ^ (tt >>> 8)); + out[j++] = (byte)(Si[ t3 & 0xFF] ^ tt ); + tt = Kdr[3]; + out[j++] = (byte)(Si[(t3 >>> 24) ] ^ (tt >>> 24)); + out[j++] = (byte)(Si[(t2 >>> 16) & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte)(Si[(t1 >>> 8) & 0xFF] ^ (tt >>> 8)); + out[j++] = (byte)(Si[ t0 & 0xFF] ^ tt ); + if (Configuration.DEBUG) + log.fine("PT=" + Util.toString(out, j - 16, 16)); + } + + public Object clone() + { + Rijndael result = new Rijndael(); + result.currentBlockSize = this.currentBlockSize; + + return result; + } + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(128 / 8)); + al.add(Integer.valueOf(192 / 8)); + al.add(Integer.valueOf(256 / 8)); + + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(128 / 8)); + al.add(Integer.valueOf(192 / 8)); + al.add(Integer.valueOf(256 / 8)); + + return Collections.unmodifiableList(al).iterator(); + } + + /** + * Expands a user-supplied key material into a session key for a designated + * block size. + * + * @param k the 128/192/256-bit user-key to use. + * @param bs the block size in bytes of this Rijndael. + * @return an Object encapsulating the session key. + * @exception IllegalArgumentException if the block size is not 16, 24 or 32. + * @exception InvalidKeyException if the key data is invalid. + */ + public Object makeKey(byte[] k, int bs) throws InvalidKeyException + { + if (k == null) + throw new InvalidKeyException("Empty key"); + if (! (k.length == 16 || k.length == 24 || k.length == 32)) + throw new InvalidKeyException("Incorrect key length"); + if (! (bs == 16 || bs == 24 || bs == 32)) + throw new IllegalArgumentException(); + int ROUNDS = getRounds(k.length, bs); + int BC = bs / 4; + int[][] Ke = new int[ROUNDS + 1][BC]; // encryption round keys + int[][] Kd = new int[ROUNDS + 1][BC]; // decryption round keys + int ROUND_KEY_COUNT = (ROUNDS + 1) * BC; + int KC = k.length / 4; + int[] tk = new int[KC]; + int i, j; + // copy user material bytes into temporary ints + for (i = 0, j = 0; i < KC;) + tk[i++] = k[j++] << 24 + | (k[j++] & 0xFF) << 16 + | (k[j++] & 0xFF) << 8 + | (k[j++] & 0xFF); + // copy values into round key arrays + int t = 0; + for (j = 0; (j < KC) && (t < ROUND_KEY_COUNT); j++, t++) + { + Ke[t / BC][t % BC] = tk[j]; + Kd[ROUNDS - (t / BC)][t % BC] = tk[j]; + } + int tt, rconpointer = 0; + while (t < ROUND_KEY_COUNT) + { + // extrapolate using phi (the round key evolution function) + tt = tk[KC - 1]; + tk[0] ^= (S[(tt >>> 16) & 0xFF] & 0xFF) << 24 + ^ (S[(tt >>> 8) & 0xFF] & 0xFF) << 16 + ^ (S[ tt & 0xFF] & 0xFF) << 8 + ^ (S[(tt >>> 24) ] & 0xFF) ^ rcon[rconpointer++] << 24; + if (KC != 8) + for (i = 1, j = 0; i < KC;) + tk[i++] ^= tk[j++]; + else + { + for (i = 1, j = 0; i < KC / 2;) + tk[i++] ^= tk[j++]; + tt = tk[KC / 2 - 1]; + tk[KC / 2] ^= (S[ tt & 0xFF] & 0xFF) + ^ (S[(tt >>> 8) & 0xFF] & 0xFF) << 8 + ^ (S[(tt >>> 16) & 0xFF] & 0xFF) << 16 + ^ S[(tt >>> 24) & 0xFF] << 24; + for (j = KC / 2, i = j + 1; i < KC;) + tk[i++] ^= tk[j++]; + } + // copy values into round key arrays + for (j = 0; (j < KC) && (t < ROUND_KEY_COUNT); j++, t++) + { + Ke[t / BC][t % BC] = tk[j]; + Kd[ROUNDS - (t / BC)][t % BC] = tk[j]; + } + } + for (int r = 1; r < ROUNDS; r++) // inverse MixColumn where needed + for (j = 0; j < BC; j++) + { + tt = Kd[r][j]; + Kd[r][j] = U1[(tt >>> 24) ] + ^ U2[(tt >>> 16) & 0xFF] + ^ U3[(tt >>> 8) & 0xFF] + ^ U4[ tt & 0xFF]; + } + return new Object[] { Ke, Kd }; + } + + public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + if (! (bs == 16 || bs == 24 || bs == 32)) + throw new IllegalArgumentException(); + if (bs == DEFAULT_BLOCK_SIZE) + aesEncrypt(in, i, out, j, k); + else + rijndaelEncrypt(in, i, out, j, k, bs); + } + + public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + if (! (bs == 16 || bs == 24 || bs == 32)) + throw new IllegalArgumentException(); + if (bs == DEFAULT_BLOCK_SIZE) + aesDecrypt(in, i, out, j, k); + else + rijndaelDecrypt(in, i, out, j, k, bs); + } + + public boolean selfTest() + { + if (valid == null) + { + boolean result = super.selfTest(); // do symmetry tests + if (result) + result = testKat(KAT_KEY, KAT_CT); + valid = Boolean.valueOf(result); + } + return valid.booleanValue(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/Serpent.java b/libjava/classpath/gnu/javax/crypto/cipher/Serpent.java new file mode 100644 index 000000000..1175fcfd2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/Serpent.java @@ -0,0 +1,1781 @@ +/* Serpent.java -- + 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.crypto.cipher; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; + +/** + * Serpent is a 32-round substitution-permutation network block cipher, + * operating on 128-bit blocks and accepting keys of 128, 192, and 256 bits in + * length. At each round the plaintext is XORed with a 128 bit portion of the + * session key -- a 4224 bit key computed from the input key -- then one of + * eight S-boxes are applied, and finally a simple linear transformation is + * done. Decryption does the exact same thing in reverse order, and using the + * eight inverses of the S-boxes. + *

+ * Serpent was designed by Ross Anderson, Eli Biham, and Lars Knudsen as a + * proposed cipher for the Advanced Encryption Standard. + *

+ * Serpent can be sped up greatly by replacing S-box substitution with a + * sequence of binary operations, and the optimal implementation depends upon + * finding the fastest sequence of binary operations that reproduce this + * substitution. This implementation uses the S-boxes discovered by Dag Arne Osvik, which are optimized + * for the Pentium family of processors. + *

+ * References: + *

    + *
  1. Serpent: A + * Candidate Block Cipher for the Advanced Encryption Standard.
  2. + *
+ */ +public class Serpent + extends BaseCipher +{ + private static final int DEFAULT_KEY_SIZE = 16; + private static final int DEFAULT_BLOCK_SIZE = 16; + private static final int ROUNDS = 32; + /** The fractional part of the golden ratio, (sqrt(5)+1)/2. */ + private static final int PHI = 0x9e3779b9; + /** + * KAT vector (from ecb_vk): I=9 + * KEY=008000000000000000000000000000000000000000000000 + * CT=5587B5BCB9EE5A28BA2BACC418005240 + */ + private static final byte[] KAT_KEY = Util.toReversedBytesFromString( + "008000000000000000000000000000000000000000000000"); + private static final byte[] KAT_CT = + Util.toReversedBytesFromString("5587B5BCB9EE5A28BA2BACC418005240"); + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + private int x0, x1, x2, x3, x4; + + /** Trivial zero-argument constructor. */ + public Serpent() + { + super(Registry.SERPENT_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + public Object clone() + { + Serpent result = new Serpent(); + result.currentBlockSize = this.currentBlockSize; + return result; + } + + public Iterator blockSizes() + { + return Collections.singleton(Integer.valueOf(DEFAULT_BLOCK_SIZE)).iterator(); + } + + public Iterator keySizes() + { + ArrayList keySizes = new ArrayList(); + keySizes.add(Integer.valueOf(16)); + keySizes.add(Integer.valueOf(24)); + keySizes.add(Integer.valueOf(32)); + return Collections.unmodifiableList(keySizes).iterator(); + } + + public Object makeKey(byte[] kb, int blockSize) throws InvalidKeyException + { + // Not strictly true, but here to conform with the AES proposal. + // This restriction can be removed if deemed necessary. + if (kb.length != 16 && kb.length != 24 && kb.length != 32) + throw new InvalidKeyException("Key length is not 16, 24, or 32 bytes"); + Key key = new Key(); + // Here w is our "pre-key". + int[] w = new int[4 * (ROUNDS + 1)]; + int i, j; + for (i = 0, j = 0; i < 8 && j < kb.length; i++) + w[i] = (kb[j++] & 0xff) + | (kb[j++] & 0xff) << 8 + | (kb[j++] & 0xff) << 16 + | (kb[j++] & 0xff) << 24; + // Pad key if < 256 bits. + if (i != 8) + w[i] = 1; + // Transform using w_i-8 ... w_i-1 + for (i = 8, j = 0; i < 16; i++) + { + int t = w[j] ^ w[i - 5] ^ w[i - 3] ^ w[i - 1] ^ PHI ^ j++; + w[i] = t << 11 | t >>> 21; + } + // Translate by 8. + for (i = 0; i < 8; i++) + w[i] = w[i + 8]; + // Transform the rest of the key. + for (; i < w.length; i++) + { + int t = w[i - 8] ^ w[i - 5] ^ w[i - 3] ^ w[i - 1] ^ PHI ^ i; + w[i] = t << 11 | t >>> 21; + } + // After these s-boxes the pre-key (w, above) will become the + // session key (key, below). + sbox3(w[0], w[1], w[2], w[3]); + key.k0 = x0; + key.k1 = x1; + key.k2 = x2; + key.k3 = x3; + sbox2(w[4], w[5], w[6], w[7]); + key.k4 = x0; + key.k5 = x1; + key.k6 = x2; + key.k7 = x3; + sbox1(w[8], w[9], w[10], w[11]); + key.k8 = x0; + key.k9 = x1; + key.k10 = x2; + key.k11 = x3; + sbox0(w[12], w[13], w[14], w[15]); + key.k12 = x0; + key.k13 = x1; + key.k14 = x2; + key.k15 = x3; + sbox7(w[16], w[17], w[18], w[19]); + key.k16 = x0; + key.k17 = x1; + key.k18 = x2; + key.k19 = x3; + sbox6(w[20], w[21], w[22], w[23]); + key.k20 = x0; + key.k21 = x1; + key.k22 = x2; + key.k23 = x3; + sbox5(w[24], w[25], w[26], w[27]); + key.k24 = x0; + key.k25 = x1; + key.k26 = x2; + key.k27 = x3; + sbox4(w[28], w[29], w[30], w[31]); + key.k28 = x0; + key.k29 = x1; + key.k30 = x2; + key.k31 = x3; + sbox3(w[32], w[33], w[34], w[35]); + key.k32 = x0; + key.k33 = x1; + key.k34 = x2; + key.k35 = x3; + sbox2(w[36], w[37], w[38], w[39]); + key.k36 = x0; + key.k37 = x1; + key.k38 = x2; + key.k39 = x3; + sbox1(w[40], w[41], w[42], w[43]); + key.k40 = x0; + key.k41 = x1; + key.k42 = x2; + key.k43 = x3; + sbox0(w[44], w[45], w[46], w[47]); + key.k44 = x0; + key.k45 = x1; + key.k46 = x2; + key.k47 = x3; + sbox7(w[48], w[49], w[50], w[51]); + key.k48 = x0; + key.k49 = x1; + key.k50 = x2; + key.k51 = x3; + sbox6(w[52], w[53], w[54], w[55]); + key.k52 = x0; + key.k53 = x1; + key.k54 = x2; + key.k55 = x3; + sbox5(w[56], w[57], w[58], w[59]); + key.k56 = x0; + key.k57 = x1; + key.k58 = x2; + key.k59 = x3; + sbox4(w[60], w[61], w[62], w[63]); + key.k60 = x0; + key.k61 = x1; + key.k62 = x2; + key.k63 = x3; + sbox3(w[64], w[65], w[66], w[67]); + key.k64 = x0; + key.k65 = x1; + key.k66 = x2; + key.k67 = x3; + sbox2(w[68], w[69], w[70], w[71]); + key.k68 = x0; + key.k69 = x1; + key.k70 = x2; + key.k71 = x3; + sbox1(w[72], w[73], w[74], w[75]); + key.k72 = x0; + key.k73 = x1; + key.k74 = x2; + key.k75 = x3; + sbox0(w[76], w[77], w[78], w[79]); + key.k76 = x0; + key.k77 = x1; + key.k78 = x2; + key.k79 = x3; + sbox7(w[80], w[81], w[82], w[83]); + key.k80 = x0; + key.k81 = x1; + key.k82 = x2; + key.k83 = x3; + sbox6(w[84], w[85], w[86], w[87]); + key.k84 = x0; + key.k85 = x1; + key.k86 = x2; + key.k87 = x3; + sbox5(w[88], w[89], w[90], w[91]); + key.k88 = x0; + key.k89 = x1; + key.k90 = x2; + key.k91 = x3; + sbox4(w[92], w[93], w[94], w[95]); + key.k92 = x0; + key.k93 = x1; + key.k94 = x2; + key.k95 = x3; + sbox3(w[96], w[97], w[98], w[99]); + key.k96 = x0; + key.k97 = x1; + key.k98 = x2; + key.k99 = x3; + sbox2(w[100], w[101], w[102], w[103]); + key.k100 = x0; + key.k101 = x1; + key.k102 = x2; + key.k103 = x3; + sbox1(w[104], w[105], w[106], w[107]); + key.k104 = x0; + key.k105 = x1; + key.k106 = x2; + key.k107 = x3; + sbox0(w[108], w[109], w[110], w[111]); + key.k108 = x0; + key.k109 = x1; + key.k110 = x2; + key.k111 = x3; + sbox7(w[112], w[113], w[114], w[115]); + key.k112 = x0; + key.k113 = x1; + key.k114 = x2; + key.k115 = x3; + sbox6(w[116], w[117], w[118], w[119]); + key.k116 = x0; + key.k117 = x1; + key.k118 = x2; + key.k119 = x3; + sbox5(w[120], w[121], w[122], w[123]); + key.k120 = x0; + key.k121 = x1; + key.k122 = x2; + key.k123 = x3; + sbox4(w[124], w[125], w[126], w[127]); + key.k124 = x0; + key.k125 = x1; + key.k126 = x2; + key.k127 = x3; + sbox3(w[128], w[129], w[130], w[131]); + key.k128 = x0; + key.k129 = x1; + key.k130 = x2; + key.k131 = x3; + return key; + } + + public synchronized void encrypt(byte[] in, int i, byte[] out, int o, + Object K, int bs) + { + Key key = (Key) K; + x0 = (in[i ] & 0xff) + | (in[i + 1] & 0xff) << 8 + | (in[i + 2] & 0xff) << 16 + | (in[i + 3] & 0xff) << 24; + x1 = (in[i + 4] & 0xff) + | (in[i + 5] & 0xff) << 8 + | (in[i + 6] & 0xff) << 16 + | (in[i + 7] & 0xff) << 24; + x2 = (in[i + 8] & 0xff) + | (in[i + 9] & 0xff) << 8 + | (in[i + 10] & 0xff) << 16 + | (in[i + 11] & 0xff) << 24; + x3 = (in[i + 12] & 0xff) + | (in[i + 13] & 0xff) << 8 + | (in[i + 14] & 0xff) << 16 + | (in[i + 15] & 0xff) << 24; + x0 ^= key.k0; + x1 ^= key.k1; + x2 ^= key.k2; + x3 ^= key.k3; + sbox0(); + x1 ^= key.k4; + x4 ^= key.k5; + x2 ^= key.k6; + x0 ^= key.k7; + sbox1(); + x0 ^= key.k8; + x4 ^= key.k9; + x2 ^= key.k10; + x1 ^= key.k11; + sbox2(); + x2 ^= key.k12; + x1 ^= key.k13; + x4 ^= key.k14; + x3 ^= key.k15; + sbox3(); + x1 ^= key.k16; + x4 ^= key.k17; + x3 ^= key.k18; + x0 ^= key.k19; + sbox4(); + x4 ^= key.k20; + x2 ^= key.k21; + x1 ^= key.k22; + x0 ^= key.k23; + sbox5(); + x2 ^= key.k24; + x0 ^= key.k25; + x4 ^= key.k26; + x1 ^= key.k27; + sbox6(); + x2 ^= key.k28; + x0 ^= key.k29; + x3 ^= key.k30; + x4 ^= key.k31; + sbox7(); + x0 = x3; + x3 = x2; + x2 = x4; + x0 ^= key.k32; + x1 ^= key.k33; + x2 ^= key.k34; + x3 ^= key.k35; + sbox0(); + x1 ^= key.k36; + x4 ^= key.k37; + x2 ^= key.k38; + x0 ^= key.k39; + sbox1(); + x0 ^= key.k40; + x4 ^= key.k41; + x2 ^= key.k42; + x1 ^= key.k43; + sbox2(); + x2 ^= key.k44; + x1 ^= key.k45; + x4 ^= key.k46; + x3 ^= key.k47; + sbox3(); + x1 ^= key.k48; + x4 ^= key.k49; + x3 ^= key.k50; + x0 ^= key.k51; + sbox4(); + x4 ^= key.k52; + x2 ^= key.k53; + x1 ^= key.k54; + x0 ^= key.k55; + sbox5(); + x2 ^= key.k56; + x0 ^= key.k57; + x4 ^= key.k58; + x1 ^= key.k59; + sbox6(); + x2 ^= key.k60; + x0 ^= key.k61; + x3 ^= key.k62; + x4 ^= key.k63; + sbox7(); + x0 = x3; + x3 = x2; + x2 = x4; + x0 ^= key.k64; + x1 ^= key.k65; + x2 ^= key.k66; + x3 ^= key.k67; + sbox0(); + x1 ^= key.k68; + x4 ^= key.k69; + x2 ^= key.k70; + x0 ^= key.k71; + sbox1(); + x0 ^= key.k72; + x4 ^= key.k73; + x2 ^= key.k74; + x1 ^= key.k75; + sbox2(); + x2 ^= key.k76; + x1 ^= key.k77; + x4 ^= key.k78; + x3 ^= key.k79; + sbox3(); + x1 ^= key.k80; + x4 ^= key.k81; + x3 ^= key.k82; + x0 ^= key.k83; + sbox4(); + x4 ^= key.k84; + x2 ^= key.k85; + x1 ^= key.k86; + x0 ^= key.k87; + sbox5(); + x2 ^= key.k88; + x0 ^= key.k89; + x4 ^= key.k90; + x1 ^= key.k91; + sbox6(); + x2 ^= key.k92; + x0 ^= key.k93; + x3 ^= key.k94; + x4 ^= key.k95; + sbox7(); + x0 = x3; + x3 = x2; + x2 = x4; + x0 ^= key.k96; + x1 ^= key.k97; + x2 ^= key.k98; + x3 ^= key.k99; + sbox0(); + x1 ^= key.k100; + x4 ^= key.k101; + x2 ^= key.k102; + x0 ^= key.k103; + sbox1(); + x0 ^= key.k104; + x4 ^= key.k105; + x2 ^= key.k106; + x1 ^= key.k107; + sbox2(); + x2 ^= key.k108; + x1 ^= key.k109; + x4 ^= key.k110; + x3 ^= key.k111; + sbox3(); + x1 ^= key.k112; + x4 ^= key.k113; + x3 ^= key.k114; + x0 ^= key.k115; + sbox4(); + x4 ^= key.k116; + x2 ^= key.k117; + x1 ^= key.k118; + x0 ^= key.k119; + sbox5(); + x2 ^= key.k120; + x0 ^= key.k121; + x4 ^= key.k122; + x1 ^= key.k123; + sbox6(); + x2 ^= key.k124; + x0 ^= key.k125; + x3 ^= key.k126; + x4 ^= key.k127; + sbox7noLT(); + x0 = x3; + x3 = x2; + x2 = x4; + x0 ^= key.k128; + x1 ^= key.k129; + x2 ^= key.k130; + x3 ^= key.k131; + out[o ] = (byte) x0; + out[o + 1] = (byte)(x0 >>> 8); + out[o + 2] = (byte)(x0 >>> 16); + out[o + 3] = (byte)(x0 >>> 24); + out[o + 4] = (byte) x1; + out[o + 5] = (byte)(x1 >>> 8); + out[o + 6] = (byte)(x1 >>> 16); + out[o + 7] = (byte)(x1 >>> 24); + out[o + 8] = (byte) x2; + out[o + 9] = (byte)(x2 >>> 8); + out[o + 10] = (byte)(x2 >>> 16); + out[o + 11] = (byte)(x2 >>> 24); + out[o + 12] = (byte) x3; + out[o + 13] = (byte)(x3 >>> 8); + out[o + 14] = (byte)(x3 >>> 16); + out[o + 15] = (byte)(x3 >>> 24); + } + + public synchronized void decrypt(byte[] in, int i, byte[] out, int o, + Object K, int bs) + { + Key key = (Key) K; + x0 = (in[i ] & 0xff) + | (in[i + 1] & 0xff) << 8 + | (in[i + 2] & 0xff) << 16 + | (in[i + 3] & 0xff) << 24; + x1 = (in[i + 4] & 0xff) + | (in[i + 5] & 0xff) << 8 + | (in[i + 6] & 0xff) << 16 + | (in[i + 7] & 0xff) << 24; + x2 = (in[i + 8] & 0xff) + | (in[i + 9] & 0xff) << 8 + | (in[i + 10] & 0xff) << 16 + | (in[i + 11] & 0xff) << 24; + x3 = (in[i + 12] & 0xff) + | (in[i + 13] & 0xff) << 8 + | (in[i + 14] & 0xff) << 16 + | (in[i + 15] & 0xff) << 24; + x0 ^= key.k128; + x1 ^= key.k129; + x2 ^= key.k130; + x3 ^= key.k131; + sboxI7noLT(); + x3 ^= key.k124; + x0 ^= key.k125; + x1 ^= key.k126; + x4 ^= key.k127; + sboxI6(); + x0 ^= key.k120; + x1 ^= key.k121; + x2 ^= key.k122; + x4 ^= key.k123; + sboxI5(); + x1 ^= key.k116; + x3 ^= key.k117; + x4 ^= key.k118; + x2 ^= key.k119; + sboxI4(); + x1 ^= key.k112; + x2 ^= key.k113; + x4 ^= key.k114; + x0 ^= key.k115; + sboxI3(); + x0 ^= key.k108; + x1 ^= key.k109; + x4 ^= key.k110; + x2 ^= key.k111; + sboxI2(); + x1 ^= key.k104; + x3 ^= key.k105; + x4 ^= key.k106; + x2 ^= key.k107; + sboxI1(); + x0 ^= key.k100; + x1 ^= key.k101; + x2 ^= key.k102; + x4 ^= key.k103; + sboxI0(); + x0 ^= key.k96; + x3 ^= key.k97; + x1 ^= key.k98; + x4 ^= key.k99; + sboxI7(); + x1 = x3; + x3 = x4; + x4 = x2; + x3 ^= key.k92; + x0 ^= key.k93; + x1 ^= key.k94; + x4 ^= key.k95; + sboxI6(); + x0 ^= key.k88; + x1 ^= key.k89; + x2 ^= key.k90; + x4 ^= key.k91; + sboxI5(); + x1 ^= key.k84; + x3 ^= key.k85; + x4 ^= key.k86; + x2 ^= key.k87; + sboxI4(); + x1 ^= key.k80; + x2 ^= key.k81; + x4 ^= key.k82; + x0 ^= key.k83; + sboxI3(); + x0 ^= key.k76; + x1 ^= key.k77; + x4 ^= key.k78; + x2 ^= key.k79; + sboxI2(); + x1 ^= key.k72; + x3 ^= key.k73; + x4 ^= key.k74; + x2 ^= key.k75; + sboxI1(); + x0 ^= key.k68; + x1 ^= key.k69; + x2 ^= key.k70; + x4 ^= key.k71; + sboxI0(); + x0 ^= key.k64; + x3 ^= key.k65; + x1 ^= key.k66; + x4 ^= key.k67; + sboxI7(); + x1 = x3; + x3 = x4; + x4 = x2; + x3 ^= key.k60; + x0 ^= key.k61; + x1 ^= key.k62; + x4 ^= key.k63; + sboxI6(); + x0 ^= key.k56; + x1 ^= key.k57; + x2 ^= key.k58; + x4 ^= key.k59; + sboxI5(); + x1 ^= key.k52; + x3 ^= key.k53; + x4 ^= key.k54; + x2 ^= key.k55; + sboxI4(); + x1 ^= key.k48; + x2 ^= key.k49; + x4 ^= key.k50; + x0 ^= key.k51; + sboxI3(); + x0 ^= key.k44; + x1 ^= key.k45; + x4 ^= key.k46; + x2 ^= key.k47; + sboxI2(); + x1 ^= key.k40; + x3 ^= key.k41; + x4 ^= key.k42; + x2 ^= key.k43; + sboxI1(); + x0 ^= key.k36; + x1 ^= key.k37; + x2 ^= key.k38; + x4 ^= key.k39; + sboxI0(); + x0 ^= key.k32; + x3 ^= key.k33; + x1 ^= key.k34; + x4 ^= key.k35; + sboxI7(); + x1 = x3; + x3 = x4; + x4 = x2; + x3 ^= key.k28; + x0 ^= key.k29; + x1 ^= key.k30; + x4 ^= key.k31; + sboxI6(); + x0 ^= key.k24; + x1 ^= key.k25; + x2 ^= key.k26; + x4 ^= key.k27; + sboxI5(); + x1 ^= key.k20; + x3 ^= key.k21; + x4 ^= key.k22; + x2 ^= key.k23; + sboxI4(); + x1 ^= key.k16; + x2 ^= key.k17; + x4 ^= key.k18; + x0 ^= key.k19; + sboxI3(); + x0 ^= key.k12; + x1 ^= key.k13; + x4 ^= key.k14; + x2 ^= key.k15; + sboxI2(); + x1 ^= key.k8; + x3 ^= key.k9; + x4 ^= key.k10; + x2 ^= key.k11; + sboxI1(); + x0 ^= key.k4; + x1 ^= key.k5; + x2 ^= key.k6; + x4 ^= key.k7; + sboxI0(); + x2 = x1; + x1 = x3; + x3 = x4; + x0 ^= key.k0; + x1 ^= key.k1; + x2 ^= key.k2; + x3 ^= key.k3; + out[o ] = (byte) x0; + out[o + 1] = (byte)(x0 >>> 8); + out[o + 2] = (byte)(x0 >>> 16); + out[o + 3] = (byte)(x0 >>> 24); + out[o + 4] = (byte) x1; + out[o + 5] = (byte)(x1 >>> 8); + out[o + 6] = (byte)(x1 >>> 16); + out[o + 7] = (byte)(x1 >>> 24); + out[o + 8] = (byte) x2; + out[o + 9] = (byte)(x2 >>> 8); + out[o + 10] = (byte)(x2 >>> 16); + out[o + 11] = (byte)(x2 >>> 24); + out[o + 12] = (byte) x3; + out[o + 13] = (byte)(x3 >>> 8); + out[o + 14] = (byte)(x3 >>> 16); + out[o + 15] = (byte)(x3 >>> 24); + } + + public boolean selfTest() + { + if (valid == null) + { + boolean result = super.selfTest(); // do symmetry tests + if (result) + result = testKat(KAT_KEY, KAT_CT); + valid = Boolean.valueOf(result); + } + return valid.booleanValue(); + } + + // These first few S-boxes operate directly on the "registers", + // x0..x4, and perform the linear transform. + private void sbox0() + { + x3 ^= x0; + x4 = x1; + x1 &= x3; + x4 ^= x2; + x1 ^= x0; + x0 |= x3; + x0 ^= x4; + x4 ^= x3; + x3 ^= x2; + x2 |= x1; + x2 ^= x4; + x4 ^= -1; + x4 |= x1; + x1 ^= x3; + x1 ^= x4; + x3 |= x0; + x1 ^= x3; + x4 ^= x3; + + x1 = (x1 << 13) | (x1 >>> 19); + x4 ^= x1; + x3 = x1 << 3; + x2 = (x2 << 3) | (x2 >>> 29); + x4 ^= x2; + x0 ^= x2; + x4 = (x4 << 1) | (x4 >>> 31); + x0 ^= x3; + x0 = (x0 << 7) | (x0 >>> 25); + x3 = x4; + x1 ^= x4; + x3 <<= 7; + x1 ^= x0; + x2 ^= x0; + x2 ^= x3; + x1 = (x1 << 5) | (x1 >>> 27); + x2 = (x2 << 22) | (x2 >>> 10); + } + + private void sbox1() + { + x4 = ~x4; + x3 = x1; + x1 ^= x4; + x3 |= x4; + x3 ^= x0; + x0 &= x1; + x2 ^= x3; + x0 ^= x4; + x0 |= x2; + x1 ^= x3; + x0 ^= x1; + x4 &= x2; + x1 |= x4; + x4 ^= x3; + x1 ^= x2; + x3 |= x0; + x1 ^= x3; + x3 = ~x3; + x4 ^= x0; + x3 &= x2; + x4 = ~x4; + x3 ^= x1; + x4 ^= x3; + + x0 = (x0 << 13) | (x0 >>> 19); + x4 ^= x0; + x3 = x0 << 3; + x2 = (x2 << 3) | (x2 >>> 29); + x4 ^= x2; + x1 ^= x2; + x4 = (x4 << 1) | (x4 >>> 31); + x1 ^= x3; + x1 = (x1 << 7) | (x1 >>> 25); + x3 = x4; + x0 ^= x4; + x3 <<= 7; + x0 ^= x1; + x2 ^= x1; + x2 ^= x3; + x0 = (x0 << 5) | (x0 >>> 27); + x2 = (x2 << 22) | (x2 >>> 10); + } + + private void sbox2() + { + x3 = x0; + x0 = x0 & x2; + x0 = x0 ^ x1; + x2 = x2 ^ x4; + x2 = x2 ^ x0; + x1 = x1 | x3; + x1 = x1 ^ x4; + x3 = x3 ^ x2; + x4 = x1; + x1 = x1 | x3; + x1 = x1 ^ x0; + x0 = x0 & x4; + x3 = x3 ^ x0; + x4 = x4 ^ x1; + x4 = x4 ^ x3; + x3 = ~x3; + + x2 = (x2 << 13) | (x2 >>> 19); + x1 ^= x2; + x0 = x2 << 3; + x4 = (x4 << 3) | (x4 >>> 29); + x1 ^= x4; + x3 ^= x4; + x1 = (x1 << 1) | (x1 >>> 31); + x3 ^= x0; + x3 = (x3 << 7) | (x3 >>> 25); + x0 = x1; + x2 ^= x1; + x0 <<= 7; + x2 ^= x3; + x4 ^= x3; + x4 ^= x0; + x2 = (x2 << 5) | (x2 >>> 27); + x4 = (x4 << 22) | (x4 >>> 10); + } + + private void sbox3() + { + x0 = x2; + x2 = x2 | x3; + x3 = x3 ^ x1; + x1 = x1 & x0; + x0 = x0 ^ x4; + x4 = x4 ^ x3; + x3 = x3 & x2; + x0 = x0 | x1; + x3 = x3 ^ x0; + x2 = x2 ^ x1; + x0 = x0 & x2; + x1 = x1 ^ x3; + x0 = x0 ^ x4; + x1 = x1 | x2; + x1 = x1 ^ x4; + x2 = x2 ^ x3; + x4 = x1; + x1 = x1 | x3; + x1 = x1 ^ x2; + + x1 = (x1 << 13) | (x1 >>> 19); + x4 ^= x1; + x2 = x1 << 3; + x3 = (x3 << 3) | (x3 >>> 29); + x4 ^= x3; + x0 ^= x3; + x4 = (x4 << 1) | (x4 >>> 31); + x0 ^= x2; + x0 = (x0 << 7) | (x0 >>> 25); + x2 = x4; + x1 ^= x4; + x2 <<= 7; + x1 ^= x0; + x3 ^= x0; + x3 ^= x2; + x1 = (x1 << 5) | (x1 >>> 27); + x3 = (x3 << 22) | (x3 >>> 10); + } + + private void sbox4() + { + x4 = x4 ^ x0; + x0 = ~x0; + x3 = x3 ^ x0; + x0 = x0 ^ x1; + x2 = x4; + x4 = x4 & x0; + x4 = x4 ^ x3; + x2 = x2 ^ x0; + x1 = x1 ^ x2; + x3 = x3 & x2; + x3 = x3 ^ x1; + x1 = x1 & x4; + x0 = x0 ^ x1; + x2 = x2 | x4; + x2 = x2 ^ x1; + x1 = x1 | x0; + x1 = x1 ^ x3; + x3 = x3 & x0; + x1 = ~x1; + x2 = x2 ^ x3; + + x4 = (x4 << 13) | (x4 >>> 19); + x2 ^= x4; + x3 = x4 << 3; + x1 = (x1 << 3) | (x1 >>> 29); + x2 ^= x1; + x0 ^= x1; + x2 = (x2 << 1) | (x2 >>> 31); + x0 ^= x3; + x0 = (x0 << 7) | (x0 >>> 25); + x3 = x2; + x4 ^= x2; + x3 <<= 7; + x4 ^= x0; + x1 ^= x0; + x1 ^= x3; + x4 = (x4 << 5) | (x4 >>> 27); + x1 = (x1 << 22) | (x1 >>> 10); + } + + private void sbox5() + { + x4 = x4 ^ x2; + x2 = x2 ^ x0; + x0 = ~x0; + x3 = x2; + x2 = x2 & x4; + x1 = x1 ^ x0; + x2 = x2 ^ x1; + x1 = x1 | x3; + x3 = x3 ^ x0; + x0 = x0 & x2; + x0 = x0 ^ x4; + x3 = x3 ^ x2; + x3 = x3 ^ x1; + x1 = x1 ^ x4; + x4 = x4 & x0; + x1 = ~x1; + x4 = x4 ^ x3; + x3 = x3 | x0; + x1 = x1 ^ x3; + + x2 = (x2 << 13) | (x2 >>> 19); + x0 ^= x2; + x3 = x2 << 3; + x4 = (x4 << 3) | (x4 >>> 29); + x0 ^= x4; + x1 ^= x4; + x0 = (x0 << 1) | (x0 >>> 31); + x1 ^= x3; + x1 = (x1 << 7) | (x1 >>> 25); + x3 = x0; + x2 ^= x0; + x3 <<= 7; + x2 ^= x1; + x4 ^= x1; + x4 ^= x3; + x2 = (x2 << 5) | (x2 >>> 27); + x4 = (x4 << 22) | (x4 >>> 10); + } + + private void sbox6() + { + x4 = ~x4; + x3 = x1; + x1 = x1 & x2; + x2 = x2 ^ x3; + x1 = x1 ^ x4; + x4 = x4 | x3; + x0 = x0 ^ x1; + x4 = x4 ^ x2; + x2 = x2 | x0; + x4 = x4 ^ x0; + x3 = x3 ^ x2; + x2 = x2 | x1; + x2 = x2 ^ x4; + x3 = x3 ^ x1; + x3 = x3 ^ x2; + x1 = ~x1; + x4 = x4 & x3; + x4 = x4 ^ x1; + x2 = (x2 << 13) | (x2 >>> 19); + x0 ^= x2; + x1 = x2 << 3; + x3 = (x3 << 3) | (x3 >>> 29); + x0 ^= x3; + x4 ^= x3; + x0 = (x0 << 1) | (x0 >>> 31); + x4 ^= x1; + x4 = (x4 << 7) | (x4 >>> 25); + x1 = x0; + x2 ^= x0; + x1 <<= 7; + x2 ^= x4; + x3 ^= x4; + x3 ^= x1; + x2 = (x2 << 5) | (x2 >>> 27); + x3 = (x3 << 22) | (x3 >>> 10); + } + + private void sbox7() + { + x1 = x3; + x3 = x3 & x0; + x3 = x3 ^ x4; + x4 = x4 & x0; + x1 = x1 ^ x3; + x3 = x3 ^ x0; + x0 = x0 ^ x2; + x2 = x2 | x1; + x2 = x2 ^ x3; + x4 = x4 ^ x0; + x3 = x3 ^ x4; + x4 = x4 & x2; + x4 = x4 ^ x1; + x1 = x1 ^ x3; + x3 = x3 & x2; + x1 = ~x1; + x3 = x3 ^ x1; + x1 = x1 & x2; + x0 = x0 ^ x4; + x1 = x1 ^ x0; + x3 = (x3 << 13) | (x3 >>> 19); + x1 ^= x3; + x0 = x3 << 3; + x4 = (x4 << 3) | (x4 >>> 29); + x1 ^= x4; + x2 ^= x4; + x1 = (x1 << 1) | (x1 >>> 31); + x2 ^= x0; + x2 = (x2 << 7) | (x2 >>> 25); + x0 = x1; + x3 ^= x1; + x0 <<= 7; + x3 ^= x2; + x4 ^= x2; + x4 ^= x0; + x3 = (x3 << 5) | (x3 >>> 27); + x4 = (x4 << 22) | (x4 >>> 10); + } + + /** The final S-box, with no transform. */ + private void sbox7noLT() + { + x1 = x3; + x3 = x3 & x0; + x3 = x3 ^ x4; + x4 = x4 & x0; + x1 = x1 ^ x3; + x3 = x3 ^ x0; + x0 = x0 ^ x2; + x2 = x2 | x1; + x2 = x2 ^ x3; + x4 = x4 ^ x0; + x3 = x3 ^ x4; + x4 = x4 & x2; + x4 = x4 ^ x1; + x1 = x1 ^ x3; + x3 = x3 & x2; + x1 = ~x1; + x3 = x3 ^ x1; + x1 = x1 & x2; + x0 = x0 ^ x4; + x1 = x1 ^ x0; + } + + private void sboxI7noLT() + { + x4 = x2; + x2 ^= x0; + x0 &= x3; + x2 = ~x2; + x4 |= x3; + x3 ^= x1; + x1 |= x0; + x0 ^= x2; + x2 &= x4; + x1 ^= x2; + x2 ^= x0; + x0 |= x2; + x3 &= x4; + x0 ^= x3; + x4 ^= x1; + x3 ^= x4; + x4 |= x0; + x3 ^= x2; + x4 ^= x2; + } + + private void sboxI6() + { + x1 = (x1 >>> 22) | (x1 << 10); + x3 = (x3 >>> 5) | (x3 << 27); + x2 = x0; + x1 ^= x4; + x2 <<= 7; + x3 ^= x4; + x1 ^= x2; + x3 ^= x0; + x4 = (x4 >>> 7) | (x4 << 25); + x0 = (x0 >>> 1) | (x0 << 31); + x0 ^= x3; + x2 = x3 << 3; + x4 ^= x2; + x3 = (x3 >>> 13) | (x3 << 19); + x0 ^= x1; + x4 ^= x1; + x1 = (x1 >>> 3) | (x1 << 29); + x3 ^= x1; + x2 = x1; + x1 &= x3; + x2 ^= x4; + x1 = ~x1; + x4 ^= x0; + x1 ^= x4; + x2 |= x3; + x3 ^= x1; + x4 ^= x2; + x2 ^= x0; + x0 &= x4; + x0 ^= x3; + x3 ^= x4; + x3 |= x1; + x4 ^= x0; + x2 ^= x3; + } + + private void sboxI5() + { + x2 = (x2 >>> 22) | (x2 << 10); + x0 = (x0 >>> 5) | (x0 << 27); + x3 = x1; + x2 ^= x4; + x3 <<= 7; + x0 ^= x4; + x2 ^= x3; + x0 ^= x1; + x4 = (x4 >>> 7) | (x4 << 25); + x1 = (x1 >>> 1) | (x1 << 31); + x1 ^= x0; + x3 = x0 << 3; + x4 ^= x3; + x0 = (x0 >>> 13) | (x0 << 19); + x1 ^= x2; + x4 ^= x2; + x2 = (x2 >>> 3) | (x2 << 29); + x1 = ~x1; + x3 = x4; + x2 ^= x1; + x4 |= x0; + x4 ^= x2; + x2 |= x1; + x2 &= x0; + x3 ^= x4; + x2 ^= x3; + x3 |= x0; + x3 ^= x1; + x1 &= x2; + x1 ^= x4; + x3 ^= x2; + x4 &= x3; + x3 ^= x1; + x4 ^= x0; + x4 ^= x3; + x3 = ~x3; + } + + private void sboxI4() + { + x4 = (x4 >>> 22) | (x4 << 10); + x1 = (x1 >>> 5) | (x1 << 27); + x0 = x3; + x4 ^= x2; + x0 <<= 7; + x1 ^= x2; + x4 ^= x0; + x1 ^= x3; + x2 = (x2 >>> 7) | (x2 << 25); + x3 = (x3 >>> 1) | (x3 << 31); + x3 ^= x1; + x0 = x1 << 3; + x2 ^= x0; + x1 = (x1 >>> 13) | (x1 << 19); + x3 ^= x4; + x2 ^= x4; + x4 = (x4 >>> 3) | (x4 << 29); + x0 = x4; + x4 &= x2; + x4 ^= x3; + x3 |= x2; + x3 &= x1; + x0 ^= x4; + x0 ^= x3; + x3 &= x4; + x1 = ~x1; + x2 ^= x0; + x3 ^= x2; + x2 &= x1; + x2 ^= x4; + x1 ^= x3; + x4 &= x1; + x2 ^= x1; + x4 ^= x0; + x4 |= x2; + x2 ^= x1; + x4 ^= x3; + } + + private void sboxI3() + { + x4 = (x4 >>> 22) | (x4 << 10); + x1 = (x1 >>> 5) | (x1 << 27); + x3 = x2; + x4 ^= x0; + x3 <<= 7; + x1 ^= x0; + x4 ^= x3; + x1 ^= x2; + x0 = (x0 >>> 7) | (x0 << 25); + x2 = (x2 >>> 1) | (x2 << 31); + x2 ^= x1; + x3 = x1 << 3; + x0 ^= x3; + x1 = (x1 >>> 13) | (x1 << 19); + x2 ^= x4; + x0 ^= x4; + x4 = (x4 >>> 3) | (x4 << 29); + x3 = x4; + x4 ^= x2; + x2 &= x4; + x2 ^= x1; + x1 &= x3; + x3 ^= x0; + x0 |= x2; + x0 ^= x4; + x1 ^= x3; + x4 ^= x1; + x1 |= x0; + x1 ^= x2; + x3 ^= x4; + x4 &= x0; + x2 |= x0; + x2 ^= x4; + x3 ^= x1; + x4 ^= x3; + } + + private void sboxI2() + { + x4 = (x4 >>> 22) | (x4 << 10); + x0 = (x0 >>> 5) | (x0 << 27); + x3 = x1; + x4 ^= x2; + x3 <<= 7; + x0 ^= x2; + x4 ^= x3; + x0 ^= x1; + x2 = (x2 >>> 7) | (x2 << 25); + x1 = (x1 >>> 1) | (x1 << 31); + x1 ^= x0; + x3 = x0 << 3; + x2 ^= x3; + x0 = (x0 >>> 13) | (x0 << 19); + x1 ^= x4; + x2 ^= x4; + x4 = (x4 >>> 3) | (x4 << 29); + x4 ^= x2; + x2 ^= x0; + x3 = x2; + x2 &= x4; + x2 ^= x1; + x1 |= x4; + x1 ^= x3; + x3 &= x2; + x4 ^= x2; + x3 &= x0; + x3 ^= x4; + x4 &= x1; + x4 |= x0; + x2 = ~x2; + x4 ^= x2; + x0 ^= x2; + x0 &= x1; + x2 ^= x3; + x2 ^= x0; + } + + private void sboxI1() + { + x4 = (x4 >>> 22) | (x4 << 10); + x1 = (x1 >>> 5) | (x1 << 27); + x0 = x3; + x4 ^= x2; + x0 <<= 7; + x1 ^= x2; + x4 ^= x0; + x1 ^= x3; + x2 = (x2 >>> 7) | (x2 << 25); + x3 = (x3 >>> 1) | (x3 << 31); + x3 ^= x1; + x0 = x1 << 3; + x2 ^= x0; + x1 = (x1 >>> 13) | (x1 << 19); + x3 ^= x4; + x2 ^= x4; + x4 = (x4 >>> 3) | (x4 << 29); + x0 = x3; + x3 ^= x2; + x2 &= x3; + x0 ^= x4; + x2 ^= x1; + x1 |= x3; + x4 ^= x2; + x1 ^= x0; + x1 |= x4; + x3 ^= x2; + x1 ^= x3; + x3 |= x2; + x3 ^= x1; + x0 = ~x0; + x0 ^= x3; + x3 |= x1; + x3 ^= x1; + x3 |= x0; + x2 ^= x3; + } + + private void sboxI0() + { + x2 = (x2 >>> 22) | (x2 << 10); + x0 = (x0 >>> 5) | (x0 << 27); + x3 = x1; + x2 ^= x4; + x3 <<= 7; + x0 ^= x4; + x2 ^= x3; + x0 ^= x1; + x4 = (x4 >>> 7) | (x4 << 25); + x1 = (x1 >>> 1) | (x1 << 31); + x1 ^= x0; + x3 = x0 << 3; + x4 ^= x3; + x0 = (x0 >>> 13) | (x0 << 19); + x1 ^= x2; + x4 ^= x2; + x2 = (x2 >>> 3) | (x2 << 29); + x2 = ~x2; + x3 = x1; + x1 |= x0; + x3 = ~x3; + x1 ^= x2; + x2 |= x3; + x1 ^= x4; + x0 ^= x3; + x2 ^= x0; + x0 &= x4; + x3 ^= x0; + x0 |= x1; + x0 ^= x2; + x4 ^= x3; + x2 ^= x1; + x4 ^= x0; + x4 ^= x1; + x2 &= x4; + x3 ^= x2; + } + + private void sboxI7() + { + x1 = (x1 >>> 22) | (x1 << 10); + x0 = (x0 >>> 5) | (x0 << 27); + x2 = x3; + x1 ^= x4; + x2 <<= 7; + x0 ^= x4; + x1 ^= x2; + x0 ^= x3; + x4 = (x4 >>> 7) | (x4 << 25); + x3 = (x3 >>> 1) | (x3 << 31); + x3 ^= x0; + x2 = x0 << 3; + x4 ^= x2; + x0 = (x0 >>> 13) | (x0 << 19); + x3 ^= x1; + x4 ^= x1; + x1 = (x1 >>> 3) | (x1 << 29); + x2 = x1; + x1 ^= x0; + x0 &= x4; + x1 = ~x1; + x2 |= x4; + x4 ^= x3; + x3 |= x0; + x0 ^= x1; + x1 &= x2; + x3 ^= x1; + x1 ^= x0; + x0 |= x1; + x4 &= x2; + x0 ^= x4; + x2 ^= x3; + x4 ^= x2; + x2 |= x0; + x4 ^= x1; + x2 ^= x1; + } + + /** S-Box 0. */ + private void sbox0(int r0, int r1, int r2, int r3) + { + int r4 = r1 ^ r2; + r3 ^= r0; + r1 = r1 & r3 ^ r0; + r0 = (r0 | r3) ^ r4; + r4 ^= r3; + r3 ^= r2; + r2 = (r2 | r1) ^ r4; + r4 = ~r4 | r1; + r1 ^= r3 ^ r4; + r3 |= r0; + x0 = r1 ^ r3; + x1 = r4 ^ r3; + x2 = r2; + x3 = r0; + } + + /** S-Box 1. */ + private void sbox1(int r0, int r1, int r2, int r3) + { + r0 = ~r0; + int r4 = r0; + r2 = ~r2; + r0 &= r1; + r2 ^= r0; + r0 |= r3; + r3 ^= r2; + r1 ^= r0; + r0 ^= r4; + r4 |= r1; + r1 ^= r3; + r2 = (r2 | r0) & r4; + r0 ^= r1; + x0 = r2; + x1 = r0 & r2 ^ r4; + x2 = r3; + x3 = r1 & r2 ^ r0; + } + + /** S-Box 2. */ + private void sbox2(int r0, int r1, int r2, int r3) + { + int r4 = r0; + r0 = r0 & r2 ^ r3; + r2 = r2 ^ r1 ^ r0; + r3 = (r3 | r4) ^ r1; + r4 ^= r2; + r1 = r3; + r3 = (r3 | r4) ^ r0; + r0 &= r1; + r4 ^= r0; + x0 = r2; + x1 = r3; + x2 = r1 ^ r3 ^ r4; + x3 = ~r4; + } + + /** S-Box 3. */ + private void sbox3(int r0, int r1, int r2, int r3) + { + int r4 = r0; + r0 |= r3; + r3 ^= r1; + r1 &= r4; + r4 = r4 ^ r2 | r1; + r2 ^= r3; + r3 = r3 & r0 ^ r4; + r0 ^= r1; + r4 = r4 & r0 ^ r2; + r1 = (r1 ^ r3 | r0) ^ r2; + r0 ^= r3; + x0 = (r1 | r3) ^ r0; + x1 = r1; + x2 = r3; + x3 = r4; + } + + /** S-Box 4. */ + private void sbox4(int r0, int r1, int r2, int r3) + { + r1 ^= r3; + int r4 = r1; + r3 = ~r3; + r2 ^= r3; + r3 ^= r0; + r1 = r1 & r3 ^ r2; + r4 ^= r3; + r0 ^= r4; + r2 = r2 & r4 ^ r0; + r0 &= r1; + r3 ^= r0; + r4 = (r4 | r1) ^ r0; + x0 = r1; + x1 = r4 ^ (r2 & r3); + x2 = ~((r0 | r3) ^ r2); + x3 = r3; + } + + /** S-Box 5. */ + private void sbox5(int r0, int r1, int r2, int r3) + { + r0 ^= r1; + r1 ^= r3; + int r4 = r1; + r3 = ~r3; + r1 &= r0; + r2 ^= r3; + r1 ^= r2; + r2 |= r4; + r4 ^= r3; + r3 = r3 & r1 ^ r0; + r4 = r4 ^ r1 ^ r2; + x0 = r1; + x1 = r3; + x2 = r0 & r3 ^ r4; + x3 = ~(r2 ^ r0) ^ (r4 | r3); + } + + /** S-Box 6. */ + private void sbox6(int r0, int r1, int r2, int r3) + { + int r4 = r3; + r2 = ~r2; + r3 = r3 & r0 ^ r2; + r0 ^= r4; + r2 = (r2 | r4) ^ r0; + r1 ^= r3; + r0 |= r1; + r2 ^= r1; + r4 ^= r0; + r0 = (r0 | r3) ^ r2; + r4 = r4 ^ r3 ^ r0; + x0 = r0; + x1 = r1; + x2 = r4; + x3 = r2 & r4 ^ ~r3; + } + + /** S-Box 7. */ + private void sbox7(int r0, int r1, int r2, int r3) + { + int r4 = r1; + r1 = (r1 | r2) ^ r3; + r4 ^= r2; + r2 ^= r1; + r3 = (r3 | r4) & r0; + r4 ^= r2; + r3 ^= r1; + r1 = (r1 | r4) ^ r0; + r0 = (r0 | r4) ^ r2; + r1 ^= r4; + r2 ^= r1; + x0 = r4 ^ (~r2 | r0); + x1 = r3; + x2 = r1 & r0 ^ r4; + x3 = r0; + } + + private class Key + implements Cloneable + { + int k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15, + k16, k17, k18, k19, k20, k21, k22, k23, k24, k25, k26, k27, k28, k29, + k30, k31, k32, k33, k34, k35, k36, k37, k38, k39, k40, k41, k42, k43, + k44, k45, k46, k47, k48, k49, k50, k51, k52, k53, k54, k55, k56, k57, + k58, k59, k60, k61, k62, k63, k64, k65, k66, k67, k68, k69, k70, k71, + k72, k73, k74, k75, k76, k77, k78, k79, k80, k81, k82, k83, k84, k85, + k86, k87, k88, k89, k90, k91, k92, k93, k94, k95, k96, k97, k98, k99, + k100, k101, k102, k103, k104, k105, k106, k107, k108, k109, k110, k111, + k112, k113, k114, k115, k116, k117, k118, k119, k120, k121, k122, k123, + k124, k125, k126, k127, k128, k129, k130, k131; + + /** Trivial 0-arguments constructor. */ + Key() + { + } + + /** Cloning constructor. */ + private Key(Key that) + { + this.k0 = that.k0; + this.k1 = that.k1; + this.k2 = that.k2; + this.k3 = that.k3; + this.k4 = that.k4; + this.k5 = that.k5; + this.k6 = that.k6; + this.k7 = that.k7; + this.k8 = that.k8; + this.k9 = that.k9; + this.k10 = that.k10; + this.k11 = that.k11; + this.k12 = that.k12; + this.k13 = that.k13; + this.k14 = that.k14; + this.k15 = that.k15; + this.k16 = that.k16; + this.k17 = that.k17; + this.k18 = that.k18; + this.k19 = that.k19; + this.k20 = that.k20; + this.k21 = that.k21; + this.k22 = that.k22; + this.k23 = that.k23; + this.k24 = that.k24; + this.k25 = that.k25; + this.k26 = that.k26; + this.k27 = that.k27; + this.k28 = that.k28; + this.k29 = that.k29; + this.k30 = that.k30; + this.k31 = that.k31; + this.k32 = that.k32; + this.k33 = that.k33; + this.k34 = that.k34; + this.k35 = that.k35; + this.k36 = that.k36; + this.k37 = that.k37; + this.k38 = that.k38; + this.k39 = that.k39; + this.k40 = that.k40; + this.k41 = that.k41; + this.k42 = that.k42; + this.k43 = that.k43; + this.k44 = that.k44; + this.k45 = that.k45; + this.k46 = that.k46; + this.k47 = that.k47; + this.k48 = that.k48; + this.k49 = that.k49; + this.k50 = that.k50; + this.k51 = that.k51; + this.k52 = that.k52; + this.k53 = that.k53; + this.k54 = that.k54; + this.k55 = that.k55; + this.k56 = that.k56; + this.k57 = that.k57; + this.k58 = that.k58; + this.k59 = that.k59; + this.k60 = that.k60; + this.k61 = that.k61; + this.k62 = that.k62; + this.k63 = that.k63; + this.k64 = that.k64; + this.k65 = that.k65; + this.k66 = that.k66; + this.k67 = that.k67; + this.k68 = that.k68; + this.k69 = that.k69; + this.k70 = that.k70; + this.k71 = that.k71; + this.k72 = that.k72; + this.k73 = that.k73; + this.k74 = that.k74; + this.k75 = that.k75; + this.k76 = that.k76; + this.k77 = that.k77; + this.k78 = that.k78; + this.k79 = that.k79; + this.k80 = that.k80; + this.k81 = that.k81; + this.k82 = that.k82; + this.k83 = that.k83; + this.k84 = that.k84; + this.k85 = that.k85; + this.k86 = that.k86; + this.k87 = that.k87; + this.k88 = that.k88; + this.k89 = that.k89; + this.k90 = that.k90; + this.k91 = that.k91; + this.k92 = that.k92; + this.k93 = that.k93; + this.k94 = that.k94; + this.k95 = that.k95; + this.k96 = that.k96; + this.k97 = that.k97; + this.k98 = that.k98; + this.k99 = that.k99; + this.k100 = that.k100; + this.k101 = that.k101; + this.k102 = that.k102; + this.k103 = that.k103; + this.k104 = that.k104; + this.k105 = that.k105; + this.k106 = that.k106; + this.k107 = that.k107; + this.k108 = that.k108; + this.k109 = that.k109; + this.k110 = that.k110; + this.k111 = that.k111; + this.k112 = that.k112; + this.k113 = that.k113; + this.k114 = that.k114; + this.k115 = that.k115; + this.k116 = that.k116; + this.k117 = that.k117; + this.k118 = that.k118; + this.k119 = that.k119; + this.k120 = that.k120; + this.k121 = that.k121; + this.k122 = that.k122; + this.k123 = that.k123; + this.k124 = that.k124; + this.k125 = that.k125; + this.k126 = that.k126; + this.k127 = that.k127; + this.k128 = that.k128; + this.k129 = that.k129; + this.k130 = that.k130; + this.k131 = that.k131; + } + + public Object clone() + { + return new Key(this); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/Square.java b/libjava/classpath/gnu/javax/crypto/cipher/Square.java new file mode 100644 index 000000000..231df0a47 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/Square.java @@ -0,0 +1,425 @@ +/* Square.java -- + 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.crypto.cipher; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; + +/** + * Square is a 128-bit key, 128-bit block cipher algorithm developed by Joan + * Daemen, Lars Knudsen and Vincent Rijmen. + *

+ * References: + *

    + *
  1. The block + * cipher Square.
    + * Joan Daemen, Lars Knudsen and Vincent Rijmen.
  2. + *
+ */ +public final class Square + extends BaseCipher +{ + private static final int DEFAULT_BLOCK_SIZE = 16; // in bytes + private static final int DEFAULT_KEY_SIZE = 16; // in bytes + private static final int ROUNDS = 8; + private static final int ROOT = 0x1F5; // for generating GF(2**8) + private static final int[] OFFSET = new int[ROUNDS]; + private static final String Sdata = + "\uB1CE\uC395\u5AAD\uE702\u4D44\uFB91\u0C87\uA150" + + "\uCB67\u54DD\u468F\uE14E\uF0FD\uFCEB\uF9C4\u1A6E" + + "\u5EF5\uCC8D\u1C56\u43FE\u0761\uF875\u59FF\u0322" + + "\u8AD1\u13EE\u8800\u0E34\u1580\u94E3\uEDB5\u5323" + + "\u4B47\u17A7\u9035\uABD8\uB8DF\u4F57\u9A92\uDB1B" + + "\u3CC8\u9904\u8EE0\uD77D\u85BB\u402C\u3A45\uF142" + + "\u6520\u4118\u7225\u9370\u3605\uF20B\uA379\uEC08" + + "\u2731\u32B6\u7CB0\u0A73\u5B7B\uB781\uD20D\u6A26" + + "\u9E58\u9C83\u74B3\uAC30\u7A69\u770F\uAE21\uDED0" + + "\u2E97\u10A4\u98A8\uD468\u2D62\u296D\u1649\u76C7" + + "\uE8C1\u9637\uE5CA\uF4E9\u6312\uC2A6\u14BC\uD328" + + "\uAF2F\uE624\u52C6\uA009\uBD8C\uCF5D\u115F\u01C5" + + "\u9F3D\uA29B\uC93B\uBE51\u191F\u3F5C\uB2EF\u4ACD" + + "\uBFBA\u6F64\uD9F3\u3EB4\uAADC\uD506\uC07E\uF666" + + "\u6C84\u7138\uB91D\u7F9D\u488B\u2ADA\uA533\u8239" + + "\uD678\u86FA\uE42B\uA91E\u8960\u6BEA\u554C\uF7E2"; + /** Substitution boxes for encryption and decryption. */ + private static final byte[] Se = new byte[256]; + private static final byte[] Sd = new byte[256]; + /** Transposition boxes for encryption and decryption. */ + private static final int[] Te = new int[256]; + private static final int[] Td = new int[256]; + /** + * KAT vector (from ecb_vk): I=87 KEY=00000000000000000000020000000000 + * CT=A9DF031B4E25E89F527EFFF89CB0BEBA + */ + private static final byte[] KAT_KEY = + Util.toBytesFromString("00000000000000000000020000000000"); + private static final byte[] KAT_CT = + Util.toBytesFromString("A9DF031B4E25E89F527EFFF89CB0BEBA"); + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + static + { + int i, j; + // re-construct Se box values + int limit = Sdata.length(); + char c1; + for (i = 0, j = 0; i < limit; i++) + { + c1 = Sdata.charAt(i); + Se[j++] = (byte)(c1 >>> 8); + Se[j++] = (byte) c1; + } + // compute Sd box values + for (i = 0; i < 256; i++) + Sd[Se[i] & 0xFF] = (byte) i; + // generate OFFSET values + OFFSET[0] = 1; + for (i = 1; i < ROUNDS; i++) + { + OFFSET[i] = mul(OFFSET[i - 1], 2); + OFFSET[i - 1] <<= 24; + } + OFFSET[ROUNDS - 1] <<= 24; + // generate Te and Td boxes if we're not reading their values + // Notes: + // (1) The function mul() computes the product of two elements of GF(2**8) + // with ROOT as reduction polynomial. + // (2) the values used in computing the Te and Td are the GF(2**8) + // coefficients of the diffusion polynomial c(x) and its inverse + // (modulo x**4 + 1) d(x), defined in sections 2.1 and 4 of the Square + // paper. + for (i = 0; i < 256; i++) + { + j = Se[i] & 0xFF; + Te[i] = (Se[i & 3] == 0) ? 0 + : mul(j, 2) << 24 + | j << 16 + | j << 8 + | mul(j, 3); + j = Sd[i] & 0xFF; + Td[i] = (Sd[i & 3] == 0) ? 0 + : mul(j, 14) << 24 + | mul(j, 9) << 16 + | mul(j, 13) << 8 + | mul(j, 11); + } + } + + /** Trivial 0-arguments constructor. */ + public Square() + { + super(Registry.SQUARE_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + private static void square(byte[] in, int i, byte[] out, int j, int[][] K, + int[] T, byte[] S) + { + int a = ((in[i++]) << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) ) ^ K[0][0]; + int b = ((in[i++]) << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) ) ^ K[0][1]; + int c = ((in[i++]) << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) ) ^ K[0][2]; + int d = ((in[i++]) << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i ] & 0xFF) ) ^ K[0][3]; + int r, aa, bb, cc, dd; + for (r = 1; r < ROUNDS; r++) + { // R - 1 full rounds + aa = T[(a >>> 24) ] + ^ rot32R(T[(b >>> 24) ], 8) + ^ rot32R(T[(c >>> 24) ], 16) + ^ rot32R(T[(d >>> 24) ], 24) ^ K[r][0]; + bb = T[(a >>> 16) & 0xFF] + ^ rot32R(T[(b >>> 16) & 0xFF], 8) + ^ rot32R(T[(c >>> 16) & 0xFF], 16) + ^ rot32R(T[(d >>> 16) & 0xFF], 24) ^ K[r][1]; + cc = T[(a >>> 8) & 0xFF] + ^ rot32R(T[(b >>> 8) & 0xFF], 8) + ^ rot32R(T[(c >>> 8) & 0xFF], 16) + ^ rot32R(T[(d >>> 8) & 0xFF], 24) ^ K[r][2]; + dd = T[ a & 0xFF] + ^ rot32R(T[ b & 0xFF], 8) + ^ rot32R(T[ c & 0xFF], 16) + ^ rot32R(T[ d & 0xFF], 24) ^ K[r][3]; + a = aa; + b = bb; + c = cc; + d = dd; + } + // last round (diffusion becomes only transposition) + aa = ((S[(a >>> 24) ] ) << 24 + | (S[(b >>> 24) ] & 0xFF) << 16 + | (S[(c >>> 24) ] & 0xFF) << 8 + | (S[(d >>> 24) ] & 0xFF) ) ^ K[r][0]; + bb = ((S[(a >>> 16) & 0xFF] ) << 24 + | (S[(b >>> 16) & 0xFF] & 0xFF) << 16 + | (S[(c >>> 16) & 0xFF] & 0xFF) << 8 + | (S[(d >>> 16) & 0xFF] & 0xFF) ) ^ K[r][1]; + cc = ((S[(a >>> 8) & 0xFF] ) << 24 + | (S[(b >>> 8) & 0xFF] & 0xFF) << 16 + | (S[(c >>> 8) & 0xFF] & 0xFF) << 8 + | (S[(d >>> 8) & 0xFF] & 0xFF) ) ^ K[r][2]; + dd = ((S[ a & 0xFF] ) << 24 + | (S[ b & 0xFF] & 0xFF) << 16 + | (S[ c & 0xFF] & 0xFF) << 8 + | (S[ d & 0xFF] & 0xFF) ) ^ K[r][3]; + out[j++] = (byte)(aa >>> 24); + out[j++] = (byte)(aa >>> 16); + out[j++] = (byte)(aa >>> 8); + out[j++] = (byte) aa; + out[j++] = (byte)(bb >>> 24); + out[j++] = (byte)(bb >>> 16); + out[j++] = (byte)(bb >>> 8); + out[j++] = (byte) bb; + out[j++] = (byte)(cc >>> 24); + out[j++] = (byte)(cc >>> 16); + out[j++] = (byte)(cc >>> 8); + out[j++] = (byte) cc; + out[j++] = (byte)(dd >>> 24); + out[j++] = (byte)(dd >>> 16); + out[j++] = (byte)(dd >>> 8); + out[j ] = (byte) dd; + } + + /** + * Applies the Theta function to an input in in order to produce in + * out an internal session sub-key. + *

+ * Both in and out are arrays of four ints. + *

+ * Pseudo-code is: + *

+   * for (i = 0; i < 4; i++)
+   *   {
+   *     out[i] = 0;
+   *     for (j = 0, n = 24; j < 4; j++, n -= 8)
+   *       {
+   *         k = mul(in[i] >>> 24, G[0][j]) ˆ mul(in[i] >>> 16, G[1][j])
+   *             ˆ mul(in[i] >>> 8, G[2][j]) ˆ mul(in[i], G[3][j]);
+   *         out[i] ˆ= k << n;
+   *       }
+   *   }
+   * 
+ */ + private static void transform(int[] in, int[] out) + { + int l3, l2, l1, l0, m; + for (int i = 0; i < 4; i++) + { + l3 = in[i]; + l2 = l3 >>> 8; + l1 = l3 >>> 16; + l0 = l3 >>> 24; + m = ((mul(l0, 2) ^ mul(l1, 3) ^ l2 ^ l3) & 0xFF) << 24; + m ^= ((l0 ^ mul(l1, 2) ^ mul(l2, 3) ^ l3) & 0xFF) << 16; + m ^= ((l0 ^ l1 ^ mul(l2, 2) ^ mul(l3, 3)) & 0xFF) << 8; + m ^= ((mul(l0, 3) ^ l1 ^ l2 ^ mul(l3, 2)) & 0xFF); + out[i] = m; + } + } + + /** + * Left rotate a 32-bit chunk. + * + * @param x the 32-bit data to rotate + * @param s number of places to left-rotate by + * @return the newly permutated value. + */ + private static int rot32L(int x, int s) + { + return x << s | x >>> (32 - s); + } + + /** + * Right rotate a 32-bit chunk. + * + * @param x the 32-bit data to rotate + * @param s number of places to right-rotate by + * @return the newly permutated value. + */ + private static int rot32R(int x, int s) + { + return x >>> s | x << (32 - s); + } + + /** + * Returns the product of two binary numbers a and b, using the generator ROOT + * as the modulus: p = (a * b) mod ROOT. ROOT Generates a suitable Galois + * Field in GF(2**8). + *

+ * For best performance call it with abs(b) < abs(a). + * + * @param a operand for multiply. + * @param b operand for multiply. + * @return the result of (a * b) % ROOT. + */ + private static final int mul(int a, int b) + { + if (a == 0) + return 0; + a &= 0xFF; + b &= 0xFF; + int result = 0; + while (b != 0) + { + if ((b & 0x01) != 0) + result ^= a; + b >>>= 1; + a <<= 1; + if (a > 0xFF) + a ^= ROOT; + } + return result & 0xFF; + } + + public Object clone() + { + Square result = new Square(); + result.currentBlockSize = this.currentBlockSize; + + return result; + } + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(DEFAULT_BLOCK_SIZE)); + + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(DEFAULT_KEY_SIZE)); + + return Collections.unmodifiableList(al).iterator(); + } + + public Object makeKey(byte[] uk, int bs) throws InvalidKeyException + { + if (bs != DEFAULT_BLOCK_SIZE) + throw new IllegalArgumentException(); + if (uk == null) + throw new InvalidKeyException("Empty key"); + if (uk.length != DEFAULT_KEY_SIZE) + throw new InvalidKeyException("Key is not 128-bit."); + int[][] Ke = new int[ROUNDS + 1][4]; + int[][] Kd = new int[ROUNDS + 1][4]; + int[][] tK = new int[ROUNDS + 1][4]; + int i = 0; + Ke[0][0] = (uk[i++] & 0xFF) << 24 + | (uk[i++] & 0xFF) << 16 + | (uk[i++] & 0xFF) << 8 + | (uk[i++] & 0xFF); + tK[0][0] = Ke[0][0]; + Ke[0][1] = (uk[i++] & 0xFF) << 24 + | (uk[i++] & 0xFF) << 16 + | (uk[i++] & 0xFF) << 8 + | (uk[i++] & 0xFF); + tK[0][1] = Ke[0][1]; + Ke[0][2] = (uk[i++] & 0xFF) << 24 + | (uk[i++] & 0xFF) << 16 + | (uk[i++] & 0xFF) << 8 + | (uk[i++] & 0xFF); + tK[0][2] = Ke[0][2]; + Ke[0][3] = (uk[i++] & 0xFF) << 24 + | (uk[i++] & 0xFF) << 16 + | (uk[i++] & 0xFF) << 8 + | (uk[i ] & 0xFF); + tK[0][3] = Ke[0][3]; + int j; + for (i = 1, j = 0; i < ROUNDS + 1; i++, j++) + { + tK[i][0] = tK[j][0] ^ rot32L(tK[j][3], 8) ^ OFFSET[j]; + tK[i][1] = tK[j][1] ^ tK[i][0]; + tK[i][2] = tK[j][2] ^ tK[i][1]; + tK[i][3] = tK[j][3] ^ tK[i][2]; + System.arraycopy(tK[i], 0, Ke[i], 0, 4); + transform(Ke[j], Ke[j]); + } + for (i = 0; i < ROUNDS; i++) + System.arraycopy(tK[ROUNDS - i], 0, Kd[i], 0, 4); + transform(tK[0], Kd[ROUNDS]); + return new Object[] { Ke, Kd }; + } + + public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + if (bs != DEFAULT_BLOCK_SIZE) + throw new IllegalArgumentException(); + int[][] K = (int[][])((Object[]) k)[0]; + square(in, i, out, j, K, Te, Se); + } + + public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + if (bs != DEFAULT_BLOCK_SIZE) + throw new IllegalArgumentException(); + int[][] K = (int[][])((Object[]) k)[1]; + square(in, i, out, j, K, Td, Sd); + } + + public boolean selfTest() + { + if (valid == null) + { + boolean result = super.selfTest(); // do symmetry tests + if (result) + result = testKat(KAT_KEY, KAT_CT); + valid = Boolean.valueOf(result); + } + return valid.booleanValue(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/TripleDES.java b/libjava/classpath/gnu/javax/crypto/cipher/TripleDES.java new file mode 100644 index 000000000..1d684c20a --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/TripleDES.java @@ -0,0 +1,257 @@ +/* TripleDES.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.cipher; + +import gnu.java.security.Registry; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.security.InvalidKeyException; + +/** + * Triple-DES, 3DES, or DESede is a combined cipher that uses three + * iterations of the Data Encryption Standard cipher to theoretically improve + * the security of plain DES, at the cost of speed. + *

+ * Triple-DES runs the DES algorithm three times with one, two or three + * independent 56-bit (DES) keys. When used with one DES key, the cipher behaves + * exactly like a (slower) DES. + *

+ * To encrypt: + *

Ci = Ek3 ( Ek2-1 ( + * Ek1 ( Pi ))) + *
+ *

+ * And to decrypt: + *

Pi = Ek1-1 ( + * Ek2 ( Ek3-1 ( Ci ))) + *
+ *

+ * (The "ede" comes from the encryption operation, which runs + * Encrypt-Decrypt-Encrypt) + *

+ * References: + *

    + *
  1. Bruce Schneier, Applied Cryptography: Protocols, Algorithms, and + * Source Code in C, Second Edition. (1996 John Wiley and Sons) ISBN + * 0-471-11709-9. Page 294--295.
  2. + *
+ */ +public class TripleDES + extends BaseCipher +{ + /** Triple-DES only operates on 64 bit blocks. */ + public static final int BLOCK_SIZE = 8; + /** By default, Triple-DES uses 168 bits of a parity-adjusted 192 bit key. */ + public static final int KEY_SIZE = 24; + /** The underlying DES instance. */ + private DES des; + + /** + * Default 0-arguments constructor. + */ + public TripleDES() + { + super(Registry.TRIPLEDES_CIPHER, BLOCK_SIZE, KEY_SIZE); + des = new DES(); + } + + /** + * Convenience method which calls the method with same name and three + * arguments, passing 3 as the value of the first parameter. + * + * @param kb The key bytes to adjust. + * @param offset The starting offset into the key bytes. + */ + public static void adjustParity(byte[] kb, int offset) + { + adjustParity(3, kb, offset); + } + + /** + * Adjusts, in-situ, the parity of the designated bytes, so they can be used + * as DES keys for a 3-DES 1-, 2- or 3-key cipher. + * + * @param keyCount the number of independent DES keys. Can be either + * 1, 2 or 3. Any other value + * will cause an {@link IllegalArgumentException} to be raised. + * @param kb the array containing the key bytes to adjust. MUST have at least + * 8 * keyCount bytes starting at offset position + * offset, otherwise an + * {@link ArrayIndexOutOfBoundsException} will be raised. + * @param offset the starting offset into the array. + * @see DES#adjustParity(byte[],int) + */ + public static void adjustParity(int keyCount, byte[] kb, int offset) + { + if (keyCount < 1 || keyCount > 3) + throw new IllegalArgumentException("Invalid keyCount value: " + keyCount); + DES.adjustParity(kb, offset); + if (keyCount > 1) + DES.adjustParity(kb, offset + 8); + if (keyCount > 2) + DES.adjustParity(kb, offset + 16); + } + + /** + * Convenience method which calls the method with same name and three + * arguments, passing 3 as the value of the first parameter. + * + * @param kb The key bytes to test. + * @param offset The starting offset into the key bytes. + * @return true if the bytes in kb starting at + * offset are parity adjusted. + * @see DES#isParityAdjusted(byte[],int) + * @see #adjustParity(byte[],int) + */ + public static boolean isParityAdjusted(byte[] kb, int offset) + { + return isParityAdjusted(3, kb, offset); + } + + /** + * Tests if enough bytes, expected to be used as DES keys for a 3-DES 1-, 2- + * or 3-key cipher, located in a designated byte array, has already been + * parity adjusted. + * + * @param keyCount the number of independent DES keys. Can be either + * 1, 2 or 3. Any other value + * will cause an {@link IllegalArgumentException} to be raised. + * @param kb the array containing the key bytes to test. MUST have at least + * 8 * keyCount bytes starting at offset position + * offset, otherwise an + * {@link ArrayIndexOutOfBoundsException} will be raised. + * @param offset the starting offset into the array. + * @return true if the bytes in kb starting at + * offset are parity adjusted. + * @see DES#isParityAdjusted(byte[],int) + * @see #adjustParity(int,byte[],int) + */ + public static boolean isParityAdjusted(int keyCount, byte[] kb, int offset) + { + if (keyCount < 1 || keyCount > 3) + throw new IllegalArgumentException("Invalid keyCount value: " + keyCount); + boolean result = DES.isParityAdjusted(kb, offset); + if (keyCount > 1) + result = result && DES.isParityAdjusted(kb, offset + 8); + if (keyCount > 2) + result = result && DES.isParityAdjusted(kb, offset + 16); + return result; + } + + public Object clone() + { + return new TripleDES(); + } + + public Iterator blockSizes() + { + return Collections.singleton(Integer.valueOf(BLOCK_SIZE)).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(8)); + al.add(Integer.valueOf(16)); + al.add(Integer.valueOf(24)); + return Collections.unmodifiableList(al).iterator(); + } + + public Object makeKey(byte[] kb, int bs) throws InvalidKeyException + { + if (kb.length != 8 && kb.length != 16 && kb.length != 24) + throw new InvalidKeyException("TripleDES key must be 8, 16 or 24 bytes: " + + kb.length); + Context ctx = new Context(); + byte[] k1 = new byte[DES.KEY_SIZE]; + System.arraycopy(kb, 0, k1, 0, DES.KEY_SIZE); + if (! DES.isParityAdjusted(k1, 0)) + DES.adjustParity(k1, 0); + ctx.k1 = (DES.Context) des.makeKey(k1, bs); + + if (kb.length == 8) + { + ctx.k2 = (DES.Context) des.makeKey(k1, bs); + ctx.k3 = (DES.Context) des.makeKey(k1, bs); + } + else + { + byte[] k2 = new byte[DES.KEY_SIZE]; + System.arraycopy(kb, DES.KEY_SIZE, k2, 0, DES.KEY_SIZE); + if (! DES.isParityAdjusted(k2, 0)) + DES.adjustParity(k2, 0); + ctx.k2 = (DES.Context) des.makeKey(k2, bs); + + byte[] k3 = new byte[DES.KEY_SIZE]; + if (kb.length == 16) + ctx.k3 = (DES.Context) des.makeKey(k1, bs); + else + { + System.arraycopy(kb, 2 * DES.KEY_SIZE, k3, 0, DES.KEY_SIZE); + if (! DES.isParityAdjusted(k3, 0)) + DES.adjustParity(k3, 0); + ctx.k3 = (DES.Context) des.makeKey(k3, bs); + } + } + return ctx; + } + + public void encrypt(byte[] in, int i, byte[] out, int o, Object K, int bs) + { + byte[] temp = new byte[BLOCK_SIZE]; + des.encrypt(in, i, temp, 0, ((Context) K).k1, bs); + des.decrypt(temp, 0, temp, 0, ((Context) K).k2, bs); + des.encrypt(temp, 0, out, o, ((Context) K).k3, bs); + } + + public void decrypt(byte[] in, int i, byte[] out, int o, Object K, int bs) + { + byte[] temp = new byte[BLOCK_SIZE]; + des.decrypt(in, i, temp, 0, ((Context) K).k3, bs); + des.encrypt(temp, 0, temp, 0, ((Context) K).k2, bs); + des.decrypt(temp, 0, out, o, ((Context) K).k1, bs); + } + + private final class Context + { + DES.Context k1, k2, k3; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/Twofish.java b/libjava/classpath/gnu/javax/crypto/cipher/Twofish.java new file mode 100644 index 000000000..c9789a699 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/Twofish.java @@ -0,0 +1,737 @@ +/* Twofish.java -- + 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.crypto.cipher; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.logging.Logger; + +/** + * Twofish is a balanced 128-bit Feistel cipher, consisting of 16 rounds. In + * each round, a 64-bit S-box value is computed from 64 bits of the block, and + * this value is xored into the other half of the block. The two half-blocks are + * then exchanged, and the next round begins. Before the first round, all input + * bits are xored with key-dependent "whitening" subkeys, and after the final + * round the output bits are xored with other key-dependent whitening subkeys; + * these subkeys are not used anywhere else in the algorithm. + *

+ * Twofish is designed by Bruce Schneier, Doug Whiting, John Kelsey, Chris + * Hall, David Wagner and Niels Ferguson. + *

+ * References: + *

    + *
  1. Twofish: A + * 128-bit Block Cipher.
  2. + *
+ */ +public final class Twofish + extends BaseCipher +{ + private static final Logger log = Logger.getLogger(Twofish.class.getName()); + private static final int DEFAULT_BLOCK_SIZE = 16; // in bytes + private static final int DEFAULT_KEY_SIZE = 16; // in bytes + private static final int MAX_ROUNDS = 16; // max # rounds (for allocating subkeys) + private static final int ROUNDS = MAX_ROUNDS; + // subkey array indices + private static final int INPUT_WHITEN = 0; + private static final int OUTPUT_WHITEN = INPUT_WHITEN + DEFAULT_BLOCK_SIZE / 4; + private static final int ROUND_SUBKEYS = OUTPUT_WHITEN + DEFAULT_BLOCK_SIZE / 4; + private static final int SK_STEP = 0x02020202; + private static final int SK_BUMP = 0x01010101; + private static final int SK_ROTL = 9; + private static final String[] Pm = new String[] { + // p0 + "\uA967\uB3E8\u04FD\uA376\u9A92\u8078\uE4DD\uD138" + + "\u0DC6\u3598\u18F7\uEC6C\u4375\u3726\uFA13\u9448" + + "\uF2D0\u8B30\u8454\uDF23\u195B\u3D59\uF3AE\uA282" + + "\u6301\u832E\uD951\u9B7C\uA6EB\uA5BE\u160C\uE361" + + "\uC08C\u3AF5\u732C\u250B\uBB4E\u896B\u536A\uB4F1" + + "\uE1E6\uBD45\uE2F4\uB666\uCC95\u0356\uD41C\u1ED7" + + "\uFBC3\u8EB5\uE9CF\uBFBA\uEA77\u39AF\u33C9\u6271" + + "\u8179\u09AD\u24CD\uF9D8\uE5C5\uB94D\u4408\u86E7" + + "\uA11D\uAAED\u0670\uB2D2\u417B\uA011\u31C2\u2790" + + "\u20F6\u60FF\u965C\uB1AB\u9E9C\u521B\u5F93\u0AEF" + + "\u9185\u49EE\u2D4F\u8F3B\u4787\u6D46\uD63E\u6964" + + "\u2ACE\uCB2F\uFC97\u057A\uAC7F\uD51A\u4B0E\uA75A" + + "\u2814\u3F29\u883C\u4C02\uB8DA\uB017\u551F\u8A7D" + + "\u57C7\u8D74\uB7C4\u9F72\u7E15\u2212\u5807\u9934" + + "\u6E50\uDE68\u65BC\uDBF8\uC8A8\u2B40\uDCFE\u32A4" + + "\uCA10\u21F0\uD35D\u0F00\u6F9D\u3642\u4A5E\uC1E0", + // p1 + "\u75F3\uC6F4\uDB7B\uFBC8\u4AD3\uE66B\u457D\uE84B" + + "\uD632\uD8FD\u3771\uF1E1\u300F\uF81B\u87FA\u063F" + + "\u5EBA\uAE5B\u8A00\uBC9D\u6DC1\uB10E\u805D\uD2D5" + + "\uA084\u0714\uB590\u2CA3\uB273\u4C54\u9274\u3651" + + "\u38B0\uBD5A\uFC60\u6296\u6C42\uF710\u7C28\u278C" + + "\u1395\u9CC7\u2446\u3B70\uCAE3\u85CB\u11D0\u93B8" + + "\uA683\u20FF\u9F77\uC3CC\u036F\u08BF\u40E7\u2BE2" + + "\u790C\uAA82\u413A\uEAB9\uE49A\uA497\u7EDA\u7A17" + + "\u6694\uA11D\u3DF0\uDEB3\u0B72\uA71C\uEFD1\u533E" + + "\u8F33\u265F\uEC76\u2A49\u8188\uEE21\uC41A\uEBD9" + + "\uC539\u99CD\uAD31\u8B01\u1823\uDD1F\u4E2D\uF948" + + "\u4FF2\u658E\u785C\u5819\u8DE5\u9857\u677F\u0564" + + "\uAF63\uB6FE\uF5B7\u3CA5\uCEE9\u6844\uE04D\u4369" + + "\u292E\uAC15\u59A8\u0A9E\u6E47\uDF34\u356A\uCFDC" + + "\u22C9\uC09B\u89D4\uEDAB\u12A2\u0D52\uBB02\u2FA9" + + "\uD761\u1EB4\u5004\uF6C2\u1625\u8656\u5509\uBE91" }; + /** Fixed 8x8 permutation S-boxes */ + private static final byte[][] P = new byte[2][256]; // blank final + /** + * Define the fixed p0/p1 permutations used in keyed S-box lookup. By + * changing the following constant definitions, the S-boxes will + * automatically get changed in the Twofish engine. + */ + private static final int P_00 = 1; + private static final int P_01 = 0; + private static final int P_02 = 0; + private static final int P_03 = P_01 ^ 1; + private static final int P_04 = 1; + private static final int P_10 = 0; + private static final int P_11 = 0; + private static final int P_12 = 1; + private static final int P_13 = P_11 ^ 1; + private static final int P_14 = 0; + private static final int P_20 = 1; + private static final int P_21 = 1; + private static final int P_22 = 0; + private static final int P_23 = P_21 ^ 1; + private static final int P_24 = 0; + private static final int P_30 = 0; + private static final int P_31 = 1; + private static final int P_32 = 1; + private static final int P_33 = P_31 ^ 1; + private static final int P_34 = 1; + /** Primitive polynomial for GF(256) */ + private static final int GF256_FDBK_2 = 0x169 / 2; + private static final int GF256_FDBK_4 = 0x169 / 4; + /** MDS matrix */ + private static final int[][] MDS = new int[4][256]; // blank final + private static final int RS_GF_FDBK = 0x14D; // field generator + /** + * KAT vector (from ecb_vk): + * I=183 + * KEY=0000000000000000000000000000000000000000000002000000000000000000 + * CT=F51410475B33FBD3DB2117B5C17C82D4 + */ + private static final byte[] KAT_KEY = Util.toBytesFromString( + "0000000000000000000000000000000000000000000002000000000000000000"); + private static final byte[] KAT_CT = + Util.toBytesFromString("F51410475B33FBD3DB2117B5C17C82D4"); + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + static + { + long time = System.currentTimeMillis(); + // expand the P arrays + int i; + char c; + for (i = 0; i < 256; i++) + { + c = Pm[0].charAt(i >>> 1); + P[0][i] = (byte)((i & 1) == 0 ? c >>> 8 : c); + c = Pm[1].charAt(i >>> 1); + P[1][i] = (byte)((i & 1) == 0 ? c >>> 8 : c); + } + // precompute the MDS matrix + int[] m1 = new int[2]; + int[] mX = new int[2]; + int[] mY = new int[2]; + int j; + for (i = 0; i < 256; i++) + { + j = P[0][i] & 0xFF; // compute all the matrix elements + m1[0] = j; + mX[0] = Mx_X(j) & 0xFF; + mY[0] = Mx_Y(j) & 0xFF; + j = P[1][i] & 0xFF; + m1[1] = j; + mX[1] = Mx_X(j) & 0xFF; + mY[1] = Mx_Y(j) & 0xFF; + MDS[0][i] = m1[P_00] << 0 + | mX[P_00] << 8 + | mY[P_00] << 16 + | mY[P_00] << 24; + MDS[1][i] = mY[P_10] << 0 + | mY[P_10] << 8 + | mX[P_10] << 16 + | m1[P_10] << 24; + MDS[2][i] = mX[P_20] << 0 + | mY[P_20] << 8 + | m1[P_20] << 16 + | mY[P_20] << 24; + MDS[3][i] = mX[P_30] << 0 + | m1[P_30] << 8 + | mY[P_30] << 16 + | mX[P_30] << 24; + } + time = System.currentTimeMillis() - time; + if (Configuration.DEBUG) + { + log.fine("Static Data"); + log.fine("MDS[0][]:"); + StringBuilder sb; + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(MDS[0][i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("MDS[1][]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(MDS[1][i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("MDS[2][]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(MDS[2][i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("MDS[3][]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(MDS[3][i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("Total initialization time: " + time + " ms."); + } + } + + private static final int LFSR1(int x) + { + return (x >> 1) ^ ((x & 0x01) != 0 ? GF256_FDBK_2 : 0); + } + + private static final int LFSR2(int x) + { + return (x >> 2) + ^ ((x & 0x02) != 0 ? GF256_FDBK_2 : 0) + ^ ((x & 0x01) != 0 ? GF256_FDBK_4 : 0); + } + + private static final int Mx_X(int x) + { // 5B + return x ^ LFSR2(x); + } + + private static final int Mx_Y(int x) + { // EF + return x ^ LFSR1(x) ^ LFSR2(x); + } + + /** Trivial 0-arguments constructor. */ + public Twofish() + { + super(Registry.TWOFISH_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + private static final int b0(int x) + { + return x & 0xFF; + } + + private static final int b1(int x) + { + return (x >>> 8) & 0xFF; + } + + private static final int b2(int x) + { + return (x >>> 16) & 0xFF; + } + + private static final int b3(int x) + { + return (x >>> 24) & 0xFF; + } + + /** + * Use (12, 8) Reed-Solomon code over GF(256) to produce a key S-box 32-bit + * entity from two key material 32-bit entities. + * + * @param k0 1st 32-bit entity. + * @param k1 2nd 32-bit entity. + * @return remainder polynomial generated using RS code + */ + private static final int RS_MDS_Encode(int k0, int k1) + { + int r = k1; + int i; + for (i = 0; i < 4; i++) // shift 1 byte at a time + r = RS_rem(r); + r ^= k0; + for (i = 0; i < 4; i++) + r = RS_rem(r); + return r; + } + + /** + * Reed-Solomon code parameters: (12, 8) reversible code:

+ *

+   *   g(x) = x**4 + (a + 1/a) x**3 + a x**2 + (a + 1/a) x + 1
+   * 
+ * where a = primitive root of field generator 0x14D + */ + private static final int RS_rem(int x) + { + int b = (x >>> 24) & 0xFF; + int g2 = ((b << 1) ^ ((b & 0x80) != 0 ? RS_GF_FDBK : 0)) & 0xFF; + int g3 = (b >>> 1) ^ ((b & 0x01) != 0 ? (RS_GF_FDBK >>> 1) : 0) ^ g2; + int result = (x << 8) ^ (g3 << 24) ^ (g2 << 16) ^ (g3 << 8) ^ b; + return result; + } + + private static final int F32(int k64Cnt, int x, int[] k32) + { + int b0 = b0(x); + int b1 = b1(x); + int b2 = b2(x); + int b3 = b3(x); + int k0 = k32[0]; + int k1 = k32[1]; + int k2 = k32[2]; + int k3 = k32[3]; + int result = 0; + switch (k64Cnt & 3) + { + case 1: + result = MDS[0][(P[P_01][b0] & 0xFF) ^ b0(k0)] + ^ MDS[1][(P[P_11][b1] & 0xFF) ^ b1(k0)] + ^ MDS[2][(P[P_21][b2] & 0xFF) ^ b2(k0)] + ^ MDS[3][(P[P_31][b3] & 0xFF) ^ b3(k0)]; + break; + case 0: // same as 4 + b0 = (P[P_04][b0] & 0xFF) ^ b0(k3); + b1 = (P[P_14][b1] & 0xFF) ^ b1(k3); + b2 = (P[P_24][b2] & 0xFF) ^ b2(k3); + b3 = (P[P_34][b3] & 0xFF) ^ b3(k3); + case 3: + b0 = (P[P_03][b0] & 0xFF) ^ b0(k2); + b1 = (P[P_13][b1] & 0xFF) ^ b1(k2); + b2 = (P[P_23][b2] & 0xFF) ^ b2(k2); + b3 = (P[P_33][b3] & 0xFF) ^ b3(k2); + case 2: // 128-bit keys (optimize for this case) + result = MDS[0][(P[P_01][(P[P_02][b0] & 0xFF) ^ b0(k1)] & 0xFF) ^ b0(k0)] + ^ MDS[1][(P[P_11][(P[P_12][b1] & 0xFF) ^ b1(k1)] & 0xFF) ^ b1(k0)] + ^ MDS[2][(P[P_21][(P[P_22][b2] & 0xFF) ^ b2(k1)] & 0xFF) ^ b2(k0)] + ^ MDS[3][(P[P_31][(P[P_32][b3] & 0xFF) ^ b3(k1)] & 0xFF) ^ b3(k0)]; + break; + } + return result; + } + + private static final int Fe32(int[] sBox, int x, int R) + { + return sBox[ 2 * _b(x, R ) ] + ^ sBox[ 2 * _b(x, R + 1) + 1] + ^ sBox[0x200 + 2 * _b(x, R + 2) ] + ^ sBox[0x200 + 2 * _b(x, R + 3) + 1]; + } + + private static final int _b(int x, int N) + { + switch (N % 4) + { + case 0: + return x & 0xFF; + case 1: + return (x >>> 8) & 0xFF; + case 2: + return (x >>> 16) & 0xFF; + default: + return x >>> 24; + } + } + + public Object clone() + { + Twofish result = new Twofish(); + result.currentBlockSize = this.currentBlockSize; + return result; + } + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(DEFAULT_BLOCK_SIZE)); + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(8)); // 64-bit + al.add(Integer.valueOf(16)); // 128-bit + al.add(Integer.valueOf(24)); // 192-bit + al.add(Integer.valueOf(32)); // 256-bit + return Collections.unmodifiableList(al).iterator(); + } + + /** + * Expands a user-supplied key material into a session key for a designated + * block size. + * + * @param k the 64/128/192/256-bit user-key to use. + * @param bs the desired block size in bytes. + * @return an Object encapsulating the session key. + * @exception IllegalArgumentException if the block size is not 16 (128-bit). + * @exception InvalidKeyException if the key data is invalid. + */ + public Object makeKey(byte[] k, int bs) throws InvalidKeyException + { + if (bs != DEFAULT_BLOCK_SIZE) + throw new IllegalArgumentException(); + if (k == null) + throw new InvalidKeyException("Empty key"); + int length = k.length; + if (! (length == 8 || length == 16 || length == 24 || length == 32)) + throw new InvalidKeyException("Incorrect key length"); + int k64Cnt = length / 8; + int subkeyCnt = ROUND_SUBKEYS + 2 * ROUNDS; + int[] k32e = new int[4]; // even 32-bit entities + int[] k32o = new int[4]; // odd 32-bit entities + int[] sBoxKey = new int[4]; + // split user key material into even and odd 32-bit entities and + // compute S-box keys using (12, 8) Reed-Solomon code over GF(256) + int i, j, offset = 0; + for (i = 0, j = k64Cnt - 1; i < 4 && offset < length; i++, j--) + { + k32e[i] = (k[offset++] & 0xFF) + | (k[offset++] & 0xFF) << 8 + | (k[offset++] & 0xFF) << 16 + | (k[offset++] & 0xFF) << 24; + k32o[i] = (k[offset++] & 0xFF) + | (k[offset++] & 0xFF) << 8 + | (k[offset++] & 0xFF) << 16 + | (k[offset++] & 0xFF) << 24; + sBoxKey[j] = RS_MDS_Encode(k32e[i], k32o[i]); // reverse order + } + // compute the round decryption subkeys for PHT. these same subkeys + // will be used in encryption but will be applied in reverse order. + int q, A, B; + int[] subKeys = new int[subkeyCnt]; + for (i = q = 0; i < subkeyCnt / 2; i++, q += SK_STEP) + { + A = F32(k64Cnt, q, k32e); // A uses even key entities + B = F32(k64Cnt, q + SK_BUMP, k32o); // B uses odd key entities + B = B << 8 | B >>> 24; + A += B; + subKeys[2 * i] = A; // combine with a PHT + A += B; + subKeys[2 * i + 1] = A << SK_ROTL | A >>> (32 - SK_ROTL); + } + // fully expand the table for speed + int k0 = sBoxKey[0]; + int k1 = sBoxKey[1]; + int k2 = sBoxKey[2]; + int k3 = sBoxKey[3]; + int b0, b1, b2, b3; + int[] sBox = new int[4 * 256]; + for (i = 0; i < 256; i++) + { + b0 = b1 = b2 = b3 = i; + switch (k64Cnt & 3) + { + case 1: + sBox[ 2 * i ] = MDS[0][(P[P_01][b0] & 0xFF) ^ b0(k0)]; + sBox[ 2 * i + 1] = MDS[1][(P[P_11][b1] & 0xFF) ^ b1(k0)]; + sBox[0x200 + 2 * i ] = MDS[2][(P[P_21][b2] & 0xFF) ^ b2(k0)]; + sBox[0x200 + 2 * i + 1] = MDS[3][(P[P_31][b3] & 0xFF) ^ b3(k0)]; + break; + case 0: // same as 4 + b0 = (P[P_04][b0] & 0xFF) ^ b0(k3); + b1 = (P[P_14][b1] & 0xFF) ^ b1(k3); + b2 = (P[P_24][b2] & 0xFF) ^ b2(k3); + b3 = (P[P_34][b3] & 0xFF) ^ b3(k3); + case 3: + b0 = (P[P_03][b0] & 0xFF) ^ b0(k2); + b1 = (P[P_13][b1] & 0xFF) ^ b1(k2); + b2 = (P[P_23][b2] & 0xFF) ^ b2(k2); + b3 = (P[P_33][b3] & 0xFF) ^ b3(k2); + case 2: // 128-bit keys + sBox[ 2 * i ] = MDS[0][(P[P_01][(P[P_02][b0] & 0xFF) + ^ b0(k1)] & 0xFF) ^ b0(k0)]; + sBox[ 2 * i + 1] = MDS[1][(P[P_11][(P[P_12][b1] & 0xFF) + ^ b1(k1)] & 0xFF) ^ b1(k0)]; + sBox[0x200 + 2 * i ] = MDS[2][(P[P_21][(P[P_22][b2] & 0xFF) + ^ b2(k1)] & 0xFF) ^ b2(k0)]; + sBox[0x200 + 2 * i + 1] = MDS[3][(P[P_31][(P[P_32][b3] & 0xFF) + ^ b3(k1)] & 0xFF) ^ b3(k0)]; + } + } + if (Configuration.DEBUG) + { + StringBuilder sb; + log.fine("S-box[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(sBox[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine(""); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(sBox[256 + i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine(""); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(sBox[512 + i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine(""); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(sBox[768 + i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("User (odd, even) keys --> S-Box keys:"); + for (i = 0; i < k64Cnt; i++) + log.fine("0x" + Util.toString(k32o[i]) + + " 0x" + Util.toString(k32e[i]) + + " --> 0x" + Util.toString(sBoxKey[k64Cnt - 1 - i])); + log.fine("Round keys:"); + for (i = 0; i < ROUND_SUBKEYS + 2 * ROUNDS; i += 2) + log.fine("0x" + Util.toString(subKeys[i]) + + " 0x" + Util.toString(subKeys[i + 1])); + } + return new Object[] { sBox, subKeys }; + } + + public void encrypt(byte[] in, int inOffset, byte[] out, int outOffset, + Object sessionKey, int bs) + { + if (bs != DEFAULT_BLOCK_SIZE) + throw new IllegalArgumentException(); + Object[] sk = (Object[]) sessionKey; // extract S-box and session key + int[] sBox = (int[]) sk[0]; + int[] sKey = (int[]) sk[1]; + if (Configuration.DEBUG) + log.fine("PT=" + Util.toString(in, inOffset, bs)); + int x0 = (in[inOffset++] & 0xFF) + | (in[inOffset++] & 0xFF) << 8 + | (in[inOffset++] & 0xFF) << 16 + | (in[inOffset++] & 0xFF) << 24; + int x1 = (in[inOffset++] & 0xFF) + | (in[inOffset++] & 0xFF) << 8 + | (in[inOffset++] & 0xFF) << 16 + | (in[inOffset++] & 0xFF) << 24; + int x2 = (in[inOffset++] & 0xFF) + | (in[inOffset++] & 0xFF) << 8 + | (in[inOffset++] & 0xFF) << 16 + | (in[inOffset++] & 0xFF) << 24; + int x3 = (in[inOffset++] & 0xFF) + | (in[inOffset++] & 0xFF) << 8 + | (in[inOffset++] & 0xFF) << 16 + | (in[inOffset++] & 0xFF) << 24; + x0 ^= sKey[INPUT_WHITEN]; + x1 ^= sKey[INPUT_WHITEN + 1]; + x2 ^= sKey[INPUT_WHITEN + 2]; + x3 ^= sKey[INPUT_WHITEN + 3]; + if (Configuration.DEBUG) + log.fine("PTw=" + Util.toString(x0) + Util.toString(x1) + + Util.toString(x2) + Util.toString(x3)); + int t0, t1; + int k = ROUND_SUBKEYS; + for (int R = 0; R < ROUNDS; R += 2) + { + t0 = Fe32(sBox, x0, 0); + t1 = Fe32(sBox, x1, 3); + x2 ^= t0 + t1 + sKey[k++]; + x2 = x2 >>> 1 | x2 << 31; + x3 = x3 << 1 | x3 >>> 31; + x3 ^= t0 + 2 * t1 + sKey[k++]; + if (Configuration.DEBUG) + log.fine("CT" + (R) + "=" + Util.toString(x0) + Util.toString(x1) + + Util.toString(x2) + Util.toString(x3)); + t0 = Fe32(sBox, x2, 0); + t1 = Fe32(sBox, x3, 3); + x0 ^= t0 + t1 + sKey[k++]; + x0 = x0 >>> 1 | x0 << 31; + x1 = x1 << 1 | x1 >>> 31; + x1 ^= t0 + 2 * t1 + sKey[k++]; + if (Configuration.DEBUG) + log.fine("CT" + (R + 1) + "=" + Util.toString(x0) + Util.toString(x1) + + Util.toString(x2) + Util.toString(x3)); + } + x2 ^= sKey[OUTPUT_WHITEN]; + x3 ^= sKey[OUTPUT_WHITEN + 1]; + x0 ^= sKey[OUTPUT_WHITEN + 2]; + x1 ^= sKey[OUTPUT_WHITEN + 3]; + if (Configuration.DEBUG) + log.fine("CTw=" + Util.toString(x0) + Util.toString(x1) + + Util.toString(x2) + Util.toString(x3)); + out[outOffset++] = (byte) x2; + out[outOffset++] = (byte)(x2 >>> 8); + out[outOffset++] = (byte)(x2 >>> 16); + out[outOffset++] = (byte)(x2 >>> 24); + out[outOffset++] = (byte) x3; + out[outOffset++] = (byte)(x3 >>> 8); + out[outOffset++] = (byte)(x3 >>> 16); + out[outOffset++] = (byte)(x3 >>> 24); + out[outOffset++] = (byte) x0; + out[outOffset++] = (byte)(x0 >>> 8); + out[outOffset++] = (byte)(x0 >>> 16); + out[outOffset++] = (byte)(x0 >>> 24); + out[outOffset++] = (byte) x1; + out[outOffset++] = (byte)(x1 >>> 8); + out[outOffset++] = (byte)(x1 >>> 16); + out[outOffset ] = (byte)(x1 >>> 24); + if (Configuration.DEBUG) + log.fine("CT=" + Util.toString(out, outOffset - 15, 16) + "\n"); + } + + public void decrypt(byte[] in, int inOffset, byte[] out, int outOffset, + Object sessionKey, int bs) + { + if (bs != DEFAULT_BLOCK_SIZE) + throw new IllegalArgumentException(); + Object[] sk = (Object[]) sessionKey; // extract S-box and session key + int[] sBox = (int[]) sk[0]; + int[] sKey = (int[]) sk[1]; + if (Configuration.DEBUG) + log.fine("CT=" + Util.toString(in, inOffset, bs)); + int x2 = (in[inOffset++] & 0xFF) + | (in[inOffset++] & 0xFF) << 8 + | (in[inOffset++] & 0xFF) << 16 + | (in[inOffset++] & 0xFF) << 24; + int x3 = (in[inOffset++] & 0xFF) + | (in[inOffset++] & 0xFF) << 8 + | (in[inOffset++] & 0xFF) << 16 + | (in[inOffset++] & 0xFF) << 24; + int x0 = (in[inOffset++] & 0xFF) + | (in[inOffset++] & 0xFF) << 8 + | (in[inOffset++] & 0xFF) << 16 + | (in[inOffset++] & 0xFF) << 24; + int x1 = (in[inOffset++] & 0xFF) + | (in[inOffset++] & 0xFF) << 8 + | (in[inOffset++] & 0xFF) << 16 + | (in[inOffset++] & 0xFF) << 24; + x2 ^= sKey[OUTPUT_WHITEN]; + x3 ^= sKey[OUTPUT_WHITEN + 1]; + x0 ^= sKey[OUTPUT_WHITEN + 2]; + x1 ^= sKey[OUTPUT_WHITEN + 3]; + if (Configuration.DEBUG) + log.fine("CTw=" + Util.toString(x2) + Util.toString(x3) + + Util.toString(x0) + Util.toString(x1)); + int k = ROUND_SUBKEYS + 2 * ROUNDS - 1; + int t0, t1; + for (int R = 0; R < ROUNDS; R += 2) + { + t0 = Fe32(sBox, x2, 0); + t1 = Fe32(sBox, x3, 3); + x1 ^= t0 + 2 * t1 + sKey[k--]; + x1 = x1 >>> 1 | x1 << 31; + x0 = x0 << 1 | x0 >>> 31; + x0 ^= t0 + t1 + sKey[k--]; + if (Configuration.DEBUG) + log.fine("PT" + (ROUNDS - R) + "=" + Util.toString(x2) + + Util.toString(x3) + Util.toString(x0) + Util.toString(x1)); + t0 = Fe32(sBox, x0, 0); + t1 = Fe32(sBox, x1, 3); + x3 ^= t0 + 2 * t1 + sKey[k--]; + x3 = x3 >>> 1 | x3 << 31; + x2 = x2 << 1 | x2 >>> 31; + x2 ^= t0 + t1 + sKey[k--]; + if (Configuration.DEBUG) + log.fine("PT" + (ROUNDS - R - 1) + "=" + Util.toString(x2) + + Util.toString(x3) + Util.toString(x0) + Util.toString(x1)); + } + x0 ^= sKey[INPUT_WHITEN]; + x1 ^= sKey[INPUT_WHITEN + 1]; + x2 ^= sKey[INPUT_WHITEN + 2]; + x3 ^= sKey[INPUT_WHITEN + 3]; + if (Configuration.DEBUG) + log.fine("PTw=" + Util.toString(x2) + Util.toString(x3) + + Util.toString(x0) + Util.toString(x1)); + out[outOffset++] = (byte) x0; + out[outOffset++] = (byte)(x0 >>> 8); + out[outOffset++] = (byte)(x0 >>> 16); + out[outOffset++] = (byte)(x0 >>> 24); + out[outOffset++] = (byte) x1; + out[outOffset++] = (byte)(x1 >>> 8); + out[outOffset++] = (byte)(x1 >>> 16); + out[outOffset++] = (byte)(x1 >>> 24); + out[outOffset++] = (byte) x2; + out[outOffset++] = (byte)(x2 >>> 8); + out[outOffset++] = (byte)(x2 >>> 16); + out[outOffset++] = (byte)(x2 >>> 24); + out[outOffset++] = (byte) x3; + out[outOffset++] = (byte)(x3 >>> 8); + out[outOffset++] = (byte)(x3 >>> 16); + out[outOffset ] = (byte)(x3 >>> 24); + if (Configuration.DEBUG) + log.fine("PT=" + Util.toString(out, outOffset - 15, 16) + "\n"); + } + + public boolean selfTest() + { + if (valid == null) + { + boolean result = super.selfTest(); // do symmetry tests + if (result) + result = testKat(KAT_KEY, KAT_CT); + valid = Boolean.valueOf(result); + } + return valid.booleanValue(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/WeakKeyException.java b/libjava/classpath/gnu/javax/crypto/cipher/WeakKeyException.java new file mode 100644 index 000000000..e12f899e4 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/WeakKeyException.java @@ -0,0 +1,59 @@ +/* WeakKeyException.java -- + Copyright (C) 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.crypto.cipher; + +import java.security.InvalidKeyException; + +/** + * Checked exception thrown to indicate that a weak key has been generated and + * or specified instead of a valid non-weak value. + */ +public class WeakKeyException + extends InvalidKeyException +{ + public WeakKeyException() + { + super(); + } + + public WeakKeyException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/DiffieHellmanImpl.java b/libjava/classpath/gnu/javax/crypto/jce/DiffieHellmanImpl.java new file mode 100644 index 000000000..205b5ed57 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/DiffieHellmanImpl.java @@ -0,0 +1,171 @@ +/* DiffieHellmanImpl.java -- implementation of the Diffie-Hellman key agreement. + Copyright (C) 2005, 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce; + +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +import javax.crypto.KeyAgreementSpi; +import javax.crypto.SecretKey; +import javax.crypto.ShortBufferException; +import javax.crypto.interfaces.DHPrivateKey; +import javax.crypto.interfaces.DHPublicKey; +import javax.crypto.spec.DHParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +/** + * The JCE implementation of a 2-party Diffie-Hellman key agreement. + * + * @author Casey Marshall (csm@gnu.org) + */ +public final class DiffieHellmanImpl + extends KeyAgreementSpi +{ + /** The private key being used for this agreement. */ + private DHPrivateKey key; + + /** The current result. */ + private byte[] result; + + /** True if the caller told us we are done. */ + private boolean last_phase_done; + + /** Trivial default constructor. */ + public DiffieHellmanImpl() + { + super(); + + key = null; + result = null; + last_phase_done = false; + } + + protected Key engineDoPhase(Key incoming, boolean lastPhase) + throws InvalidKeyException + { + if (key == null) + throw new IllegalStateException("Not initialized"); + + if (last_phase_done) + throw new IllegalStateException("Last phase already done"); + + if (! (incoming instanceof DHPublicKey)) + throw new InvalidKeyException("Key MUST be a DHPublicKey"); + + DHPublicKey pub = (DHPublicKey) incoming; + DHParameterSpec s1 = key.getParams(); + DHParameterSpec s2 = pub.getParams(); + if (! s1.getG().equals(s2.getG()) || ! s1.getP().equals(s2.getP())) + throw new InvalidKeyException("Incompatible key"); + if (! lastPhase) + throw new IllegalArgumentException( + "This key-agreement MUST be concluded in one step only"); + BigInteger resultBI = pub.getY().modPow(key.getX(), s1.getP()); + result = resultBI.toByteArray(); + if (result[0] == 0x00) + { + byte[] buf = new byte[result.length - 1]; + System.arraycopy(result, 1, buf, 0, buf.length); + result = buf; + } + last_phase_done = true; + return null; + } + + protected byte[] engineGenerateSecret() + { + checkState(); + byte[] res = (byte[]) result.clone(); + reset(); + return res; + } + + protected int engineGenerateSecret(byte[] secret, int offset) + throws ShortBufferException + { + checkState(); + if (result.length > secret.length - offset) + throw new ShortBufferException(); + System.arraycopy(result, 0, secret, offset, result.length); + int res = result.length; + reset(); + return res; + } + + protected SecretKey engineGenerateSecret(String algorithm) + throws InvalidKeyException + { + checkState(); + byte[] s = (byte[]) result.clone(); + SecretKey res = new SecretKeySpec(s, algorithm); + reset(); + return res; + } + + protected void engineInit(Key key, SecureRandom random) + throws InvalidKeyException + { + if (! (key instanceof DHPrivateKey)) + throw new InvalidKeyException("Key MUST be a DHPrivateKey"); + this.key = (DHPrivateKey) key; + reset(); + } + + protected void engineInit(Key key, AlgorithmParameterSpec params, + SecureRandom random) + throws InvalidKeyException + { + engineInit(key, random); + } + + private void reset() + { + result = null; + last_phase_done = false; + } + + private void checkState() + { + if (result == null || ! last_phase_done) + throw new IllegalStateException("Not finished"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/GnuCrypto.java b/libjava/classpath/gnu/javax/crypto/jce/GnuCrypto.java new file mode 100644 index 000000000..ec335b735 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/GnuCrypto.java @@ -0,0 +1,598 @@ +/* GnuCrypto.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.mac.MacFactory; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.Provider; +import java.util.HashSet; +import java.util.Set; + +/** + * The additional GNU algorithm implementation as a Java Cryptographic Extension + * (JCE) Provider. + * + * @see java.security.Provider + */ +public final class GnuCrypto + extends Provider +{ + public GnuCrypto() + { + super(Registry.GNU_CRYPTO, 2.1, "GNU Crypto JCE Provider"); + + AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + // Cipher + put("Cipher.ANUBIS", + gnu.javax.crypto.jce.cipher.AnubisSpi.class.getName()); + put("Cipher.ANUBIS ImplementedIn", "Software"); + put("Cipher.ARCFOUR", + gnu.javax.crypto.jce.cipher.ARCFourSpi.class.getName()); + put("Cipher.ARCFOUR ImplementedIn", "Software"); + put("Cipher.BLOWFISH", + gnu.javax.crypto.jce.cipher.BlowfishSpi.class.getName()); + put("Cipher.BLOWFISH ImplementedIn", "Software"); + put("Cipher.DES", gnu.javax.crypto.jce.cipher.DESSpi.class.getName()); + put("Cipher.DES ImplementedIn", "Software"); + put("Cipher.KHAZAD", + gnu.javax.crypto.jce.cipher.KhazadSpi.class.getName()); + put("Cipher.KHAZAD ImplementedIn", "Software"); + put("Cipher.NULL", + gnu.javax.crypto.jce.cipher.NullCipherSpi.class.getName()); + put("Cipher.NULL ImplementedIn", "Software"); + put("Cipher.AES", + gnu.javax.crypto.jce.cipher.RijndaelSpi.class.getName()); + put("Cipher.AES ImplementedIn", "Software"); + put("Cipher.RIJNDAEL", + gnu.javax.crypto.jce.cipher.RijndaelSpi.class.getName()); + put("Cipher.RIJNDAEL ImplementedIn", "Software"); + put("Cipher.SERPENT", + gnu.javax.crypto.jce.cipher.SerpentSpi.class.getName()); + put("Cipher.SERPENT ImplementedIn", "Software"); + put("Cipher.SQUARE", + gnu.javax.crypto.jce.cipher.SquareSpi.class.getName()); + put("Cipher.SQUARE ImplementedIn", "Software"); + put("Cipher.TRIPLEDES", + gnu.javax.crypto.jce.cipher.TripleDESSpi.class.getName()); + put("Cipher.TRIPLEDES ImplementedIn", "Software"); + put("Cipher.TWOFISH", + gnu.javax.crypto.jce.cipher.TwofishSpi.class.getName()); + put("Cipher.TWOFISH ImplementedIn", "Software"); + put("Cipher.CAST5", + gnu.javax.crypto.jce.cipher.Cast5Spi.class.getName()); + put("Cipher.CAST5 ImplementedIn", "Software"); + + // PBES2 ciphers. + put("Cipher.PBEWithHMacHavalAndAES", + gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.AES.class.getName()); + put("Cipher.PBEWithHMacHavalAndAnubis", + gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.Anubis.class.getName()); + put("Cipher.PBEWithHMacHavalAndBlowfish", + gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.Blowfish.class.getName()); + put("Cipher.PBEWithHMacHavalAndCast5", + gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.Cast5.class.getName()); + put("Cipher.PBEWithHMacHavalAndDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.DES.class.getName()); + put("Cipher.PBEWithHMacHavalAndKhazad", + gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.Khazad.class.getName()); + put("Cipher.PBEWithHMacHavalAndSerpent", + gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.Serpent.class.getName()); + put("Cipher.PBEWithHMacHavalAndSquare", + gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.Square.class.getName()); + put("Cipher.PBEWithHMacHavalAndTripleDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.TripleDES.class.getName()); + put("Cipher.PBEWithHMacHavalAndTwofish", + gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.Twofish.class.getName()); + + put("Cipher.PBEWithHMacMD2AndAES", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.AES.class.getName()); + put("Cipher.PBEWithHMacMD2AndAnubis", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.Anubis.class.getName()); + put("Cipher.PBEWithHMacMD2AndBlowfish", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.Blowfish.class.getName()); + put("Cipher.PBEWithHMacMD2AndCast5", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.Cast5.class.getName()); + put("Cipher.PBEWithHMacMD2AndDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.DES.class.getName()); + put("Cipher.PBEWithHMacMD2AndKhazad", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.Khazad.class.getName()); + put("Cipher.PBEWithHMacMD2AndSerpent", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.Serpent.class.getName()); + put("Cipher.PBEWithHMacMD2AndSquare", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.Square.class.getName()); + put("Cipher.PBEWithHMacMD2AndTripleDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.TripleDES.class.getName()); + put("Cipher.PBEWithHMacMD2AndTwofish", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.Twofish.class.getName()); + + put("Cipher.PBEWithHMacMD4AndAES", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.AES.class.getName()); + put("Cipher.PBEWithHMacMD4AndAnubis", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.Anubis.class.getName()); + put("Cipher.PBEWithHMacMD4AndBlowfish", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.Blowfish.class.getName()); + put("Cipher.PBEWithHMacMD4AndCast5", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.Cast5.class.getName()); + put("Cipher.PBEWithHMacMD4AndDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.DES.class.getName()); + put("Cipher.PBEWithHMacMD4AndKhazad", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.Khazad.class.getName()); + put("Cipher.PBEWithHMacMD4AndSerpent", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.Serpent.class.getName()); + put("Cipher.PBEWithHMacMD4AndSquare", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.Square.class.getName()); + put("Cipher.PBEWithHMacMD4AndTripleDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.TripleDES.class.getName()); + put("Cipher.PBEWithHMacMD4AndTwofish", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.Twofish.class.getName()); + + put("Cipher.PBEWithHMacMD5AndAES", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.AES.class.getName()); + put("Cipher.PBEWithHMacMD5AndAnubis", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.Anubis.class.getName()); + put("Cipher.PBEWithHMacMD5AndBlowfish", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.Blowfish.class.getName()); + put("Cipher.PBEWithHMacMD5AndCast5", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.Cast5.class.getName()); + put("Cipher.PBEWithHMacMD5AndDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.DES.class.getName()); + put("Cipher.PBEWithHMacMD5AndKhazad", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.Khazad.class.getName()); + put("Cipher.PBEWithHMacMD5AndSerpent", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.Serpent.class.getName()); + put("Cipher.PBEWithHMacMD5AndSquare", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.Square.class.getName()); + put("Cipher.PBEWithHMacMD5AndTripleDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.TripleDES.class.getName()); + put("Cipher.PBEWithHMacMD5AndTwofish", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.Twofish.class.getName()); + + put("Cipher.PBEWithHMacSHA1AndAES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.AES.class.getName()); + put("Cipher.PBEWithHMacSHA1AndAnubis", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.Anubis.class.getName()); + put("Cipher.PBEWithHMacSHA1AndBlowfish", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.Blowfish.class.getName()); + put("Cipher.PBEWithHMacSHA1AndCast5", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.Cast5.class.getName()); + put("Cipher.PBEWithHMacSHA1AndDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.DES.class.getName()); + put("Cipher.PBEWithHMacSHA1AndKhazad", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.Khazad.class.getName()); + put("Cipher.PBEWithHMacSHA1AndSerpent", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.Serpent.class.getName()); + put("Cipher.PBEWithHMacSHA1AndSquare", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.Square.class.getName()); + put( + "Cipher.PBEWithHMacSHA1AndTripleDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.TripleDES.class.getName()); + put("Cipher.PBEWithHMacSHA1AndTwofish", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.Twofish.class.getName()); + + put("Cipher.PBEWithHMacSHA256AndAES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.AES.class.getName()); + put("Cipher.PBEWithHMacSHA256AndAnubis", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.Anubis.class.getName()); + put("Cipher.PBEWithHMacSHA256AndBlowfish", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.Blowfish.class.getName()); + put("Cipher.PBEWithHMacSHA256AndCast5", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.Cast5.class.getName()); + put("Cipher.PBEWithHMacSHA256AndDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.DES.class.getName()); + put("Cipher.PBEWithHMacSHA256AndKhazad", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.Khazad.class.getName()); + put("Cipher.PBEWithHMacSHA256AndSerpent", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.Serpent.class.getName()); + put("Cipher.PBEWithHMacSHA256AndSquare", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.Square.class.getName()); + put("Cipher.PBEWithHMacSHA256AndTripleDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.TripleDES.class.getName()); + put("Cipher.PBEWithHMacSHA256AndTwofish", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.Twofish.class.getName()); + + put("Cipher.PBEWithHMacSHA384AndAES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.AES.class.getName()); + put("Cipher.PBEWithHMacSHA384AndAnubis", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.Anubis.class.getName()); + put("Cipher.PBEWithHMacSHA384AndBlowfish", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.Blowfish.class.getName()); + put("Cipher.PBEWithHMacSHA384AndCast5", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.Cast5.class.getName()); + put("Cipher.PBEWithHMacSHA384AndDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.DES.class.getName()); + put("Cipher.PBEWithHMacSHA384AndKhazad", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.Khazad.class.getName()); + put("Cipher.PBEWithHMacSHA384AndSerpent", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.Serpent.class.getName()); + put("Cipher.PBEWithHMacSHA384AndSquare", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.Square.class.getName()); + put("Cipher.PBEWithHMacSHA384AndTripleDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.TripleDES.class.getName()); + put("Cipher.PBEWithHMacSHA384AndTwofish", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.Twofish.class.getName()); + + put("Cipher.PBEWithHMacSHA512AndAES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.AES.class.getName()); + put("Cipher.PBEWithHMacSHA512AndAnubis", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.Anubis.class.getName()); + put("Cipher.PBEWithHMacSHA512AndBlowfish", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.Blowfish.class.getName()); + put("Cipher.PBEWithHMacSHA512AndCast5", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.Cast5.class.getName()); + put("Cipher.PBEWithHMacSHA512AndDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.DES.class.getName()); + put("Cipher.PBEWithHMacSHA512AndKhazad", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.Khazad.class.getName()); + put("Cipher.PBEWithHMacSHA512AndSerpent", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.Serpent.class.getName()); + put("Cipher.PBEWithHMacSHA512AndSquare", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.Square.class.getName()); + put("Cipher.PBEWithHMacSHA512AndTripleDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.TripleDES.class.getName()); + put("Cipher.PBEWithHMacSHA512AndTwofish", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.Twofish.class.getName()); + + put("Cipher.PBEWithHMacTigerAndAES", + gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.AES.class.getName()); + put("Cipher.PBEWithHMacTigerAndAnubis", + gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.Anubis.class.getName()); + put("Cipher.PBEWithHMacTigerAndBlowfish", + gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.Blowfish.class.getName()); + put("Cipher.PBEWithHMacTigerAndCast5", + gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.Cast5.class.getName()); + put("Cipher.PBEWithHMacTigerAndDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.DES.class.getName()); + put("Cipher.PBEWithHMacTigerAndKhazad", + gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.Khazad.class.getName()); + put("Cipher.PBEWithHMacTigerAndSerpent", + gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.Serpent.class.getName()); + put("Cipher.PBEWithHMacTigerAndSquare", + gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.Square.class.getName()); + put("Cipher.PBEWithHMacTigerAndTripleDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.TripleDES.class.getName()); + put("Cipher.PBEWithHMacTigerAndTwofish", + gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.Twofish.class.getName()); + + put("Cipher.PBEWithHMacWhirlpoolAndAES", + gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.AES.class.getName()); + put("Cipher.PBEWithHMacWhirlpoolAndAnubis", + gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.Anubis.class.getName()); + put("Cipher.PBEWithHMacWhirlpoolAndBlowfish", + gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.Blowfish.class.getName()); + put("Cipher.PBEWithHMacWhirlpoolAndCast5", + gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.Cast5.class.getName()); + put("Cipher.PBEWithHMacWhirlpoolAndDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.DES.class.getName()); + put("Cipher.PBEWithHMacWhirlpoolAndKhazad", + gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.Khazad.class.getName()); + put("Cipher.PBEWithHMacWhirlpoolAndSerpent", + gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.Serpent.class.getName()); + put("Cipher.PBEWithHMacWhirlpoolAndSquare", + gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.Square.class.getName()); + put("Cipher.PBEWithHMacWhirlpoolAndTripleDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.TripleDES.class.getName()); + put("Cipher.PBEWithHMacWhirlpoolAndTwofish", + gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.Twofish.class.getName()); + + // Key Wrapping Algorithm cipher + put("Cipher." + Registry.AES128_KWA, + gnu.javax.crypto.jce.cipher.AES128KeyWrapSpi.class.getName()); + put("Cipher." + Registry.AES192_KWA, + gnu.javax.crypto.jce.cipher.AES192KeyWrapSpi.class.getName()); + put("Cipher." + Registry.AES256_KWA, + gnu.javax.crypto.jce.cipher.AES256KeyWrapSpi.class.getName()); + put("Cipher." + Registry.TRIPLEDES_KWA, + gnu.javax.crypto.jce.cipher.TripleDESKeyWrapSpi.class.getName()); + + // SecretKeyFactory interface to PBKDF2. + put("SecretKeyFactory.PBKDF2WithHMacHaval", + gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacHaval.class.getName()); + put("SecretKeyFactory.PBKDF2WithHMacMD2", + gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacMD2.class.getName()); + put("SecretKeyFactory.PBKDF2WithHMacMD4", + gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacMD4.class.getName()); + put("SecretKeyFactory.PBKDF2WithHMacMD5", + gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacMD5.class.getName()); + put("SecretKeyFactory.PBKDF2WithHMacSHA1", + gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacSHA1.class.getName()); + put("SecretKeyFactory.PBKDF2WithHMacSHA256", + gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacSHA256.class.getName()); + put("SecretKeyFactory.PBKDF2WithHMacSHA384", + gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacSHA384.class.getName()); + put("SecretKeyFactory.PBKDF2WithHMacSHA512", + gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacSHA512.class.getName()); + put("SecretKeyFactory.PBKDF2WithHMacTiger", + gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacTiger.class.getName()); + put("SecretKeyFactory.PBKDF2WithHMacWhirlpool", + gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacWhirlpool.class.getName()); + + // Simple SecretKeyFactory implementations. + put("SecretKeyFactory.Anubis", + gnu.javax.crypto.jce.key.AnubisSecretKeyFactoryImpl.class.getName()); + put("SecretKeyFactory.Blowfish", + gnu.javax.crypto.jce.key.BlowfishSecretKeyFactoryImpl.class.getName()); + put("SecretKeyFactory.Cast5", + gnu.javax.crypto.jce.key.Cast5SecretKeyFactoryImpl.class.getName()); + put("SecretKeyFactory.DES", + gnu.javax.crypto.jce.key.DESSecretKeyFactoryImpl.class.getName()); + put("SecretKeyFactory.Khazad", + gnu.javax.crypto.jce.key.KhazadSecretKeyFactoryImpl.class.getName()); + put("SecretKeyFactory.Rijndael", + gnu.javax.crypto.jce.key.RijndaelSecretKeyFactoryImpl.class.getName()); + put("SecretKeyFactory.Serpent", + gnu.javax.crypto.jce.key.SerpentSecretKeyFactoryImpl.class.getName()); + put("SecretKeyFactory.Square", + gnu.javax.crypto.jce.key.SquareSecretKeyFactoryImpl.class.getName()); + put("SecretKeyFactory.TripleDES", + gnu.javax.crypto.jce.key.DESedeSecretKeyFactoryImpl.class.getName()); + put("Alg.Alias.SecretKeyFactory.AES", "Rijndael"); + put("Alg.Alias.SecretKeyFactory.DESede", "TripleDES"); + put("Alg.Alias.SecretKeyFactory.3-DES", "TripleDES"); + put("Alg.Alias.SecretKeyFactory.3DES", "TripleDES"); + + put("AlgorithmParameters.BlockCipherParameters", + gnu.javax.crypto.jce.params.BlockCipherParameters.class.getName()); + put("Alg.Alias.AlgorithmParameters.Anubis", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.Blowfish", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.Cast5", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.DES", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.Khazad", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.Rijndael", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.AES", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.Serpent", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.Square", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.TripleDES", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.DESede", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.3-DES", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.3DES", "BlockCipherParameters"); + + // KeyGenerator Adapter implementations + put("KeyGenerator.Anubis", + gnu.javax.crypto.jce.key.AnubisKeyGeneratorImpl.class.getName()); + put("KeyGenerator.Blowfish", + gnu.javax.crypto.jce.key.BlowfishKeyGeneratorImpl.class.getName()); + put("KeyGenerator.Cast5", + gnu.javax.crypto.jce.key.Cast5KeyGeneratorImpl.class.getName()); + put("KeyGenerator.DES", + gnu.javax.crypto.jce.key.DESKeyGeneratorImpl.class.getName()); + put("KeyGenerator.Khazad", + gnu.javax.crypto.jce.key.KhazadKeyGeneratorImpl.class.getName()); + put("KeyGenerator.Rijndael", + gnu.javax.crypto.jce.key.RijndaelKeyGeneratorImpl.class.getName()); + put("KeyGenerator.Serpent", + gnu.javax.crypto.jce.key.SerpentKeyGeneratorImpl.class.getName()); + put("KeyGenerator.Square", + gnu.javax.crypto.jce.key.SquareKeyGeneratorImpl.class.getName()); + put("KeyGenerator.TripleDES", + gnu.javax.crypto.jce.key.TripleDESKeyGeneratorImpl.class.getName()); + put("Alg.Alias.KeyGenerator.AES", "Rijndael"); + put("Alg.Alias.KeyGenerator.DESede", "TripleDES"); + put("Alg.Alias.KeyGenerator.3-DES", "TripleDES"); + put("Alg.Alias.KeyGenerator.3DES", "TripleDES"); + + // MAC + put("Mac.HMAC-MD2", gnu.javax.crypto.jce.mac.HMacMD2Spi.class.getName()); + put("Mac.HMAC-MD4", gnu.javax.crypto.jce.mac.HMacMD4Spi.class.getName()); + put("Mac.HMAC-MD5", gnu.javax.crypto.jce.mac.HMacMD5Spi.class.getName()); + put("Mac.HMAC-RIPEMD128", + gnu.javax.crypto.jce.mac.HMacRipeMD128Spi.class.getName()); + put("Mac.HMAC-RIPEMD160", + gnu.javax.crypto.jce.mac.HMacRipeMD160Spi.class.getName()); + put("Mac.HMAC-SHA160", + gnu.javax.crypto.jce.mac.HMacSHA160Spi.class.getName()); + put("Mac.HMAC-SHA256", + gnu.javax.crypto.jce.mac.HMacSHA256Spi.class.getName()); + put("Mac.HMAC-SHA384", + gnu.javax.crypto.jce.mac.HMacSHA384Spi.class.getName()); + put("Mac.HMAC-SHA512", + gnu.javax.crypto.jce.mac.HMacSHA512Spi.class.getName()); + put("Mac.HMAC-TIGER", + gnu.javax.crypto.jce.mac.HMacTigerSpi.class.getName()); + put("Mac.HMAC-HAVAL", + gnu.javax.crypto.jce.mac.HMacHavalSpi.class.getName()); + put("Mac.HMAC-WHIRLPOOL", + gnu.javax.crypto.jce.mac.HMacWhirlpoolSpi.class.getName()); + put("Mac.TMMH16", gnu.javax.crypto.jce.mac.TMMH16Spi.class.getName()); + put("Mac.UHASH32", gnu.javax.crypto.jce.mac.UHash32Spi.class.getName()); + put("Mac.UMAC32", gnu.javax.crypto.jce.mac.UMac32Spi.class.getName()); + + put("Mac.OMAC-ANUBIS", + gnu.javax.crypto.jce.mac.OMacAnubisImpl.class.getName()); + put("Mac.OMAC-BLOWFISH", + gnu.javax.crypto.jce.mac.OMacBlowfishImpl.class.getName()); + put("Mac.OMAC-CAST5", + gnu.javax.crypto.jce.mac.OMacCast5Impl.class.getName()); + put("Mac.OMAC-DES", + gnu.javax.crypto.jce.mac.OMacDESImpl.class.getName()); + put("Mac.OMAC-KHAZAD", + gnu.javax.crypto.jce.mac.OMacKhazadImpl.class.getName()); + put("Mac.OMAC-RIJNDAEL", + gnu.javax.crypto.jce.mac.OMacRijndaelImpl.class.getName()); + put("Mac.OMAC-SERPENT", + gnu.javax.crypto.jce.mac.OMacSerpentImpl.class.getName()); + put("Mac.OMAC-SQUARE", + gnu.javax.crypto.jce.mac.OMacSquareImpl.class.getName()); + put("Mac.OMAC-TRIPLEDES", + gnu.javax.crypto.jce.mac.OMacTripleDESImpl.class.getName()); + put("Mac.OMAC-TWOFISH", + gnu.javax.crypto.jce.mac.OMacTwofishImpl.class.getName()); + + // Aliases + put("Alg.Alias.AlgorithmParameters.AES", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.BLOWFISH", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.ANUBIS", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.KHAZAD", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.NULL", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.RIJNDAEL", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.SERPENT", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.SQUARE", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.TWOFISH", "BlockCipherParameters"); + put("Alg.Alias.Cipher.RC4", "ARCFOUR"); + put("Alg.Alias.Cipher.3-DES", "TRIPLEDES"); + put("Alg.Alias.Cipher.3DES", "TRIPLEDES"); + put("Alg.Alias.Cipher.DES-EDE", "TRIPLEDES"); + put("Alg.Alias.Cipher.DESede", "TRIPLEDES"); + put("Alg.Alias.Cipher.CAST128", "CAST5"); + put("Alg.Alias.Cipher.CAST-128", "CAST5"); + put("Alg.Alias.Mac.HMAC-SHS", "HMAC-SHA160"); + put("Alg.Alias.Mac.HMAC-SHA", "HMAC-SHA160"); + put("Alg.Alias.Mac.HMAC-SHA1", "HMAC-SHA160"); + put("Alg.Alias.Mac.HMAC-SHA-160", "HMAC-SHA160"); + put("Alg.Alias.Mac.HMAC-SHA-256", "HMAC-SHA256"); + put("Alg.Alias.Mac.HMAC-SHA-384", "HMAC-SHA384"); + put("Alg.Alias.Mac.HMAC-SHA-512", "HMAC-SHA512"); + put("Alg.Alias.Mac.HMAC-RIPEMD-160", "HMAC-RIPEMD160"); + put("Alg.Alias.Mac.HMAC-RIPEMD-128", "HMAC-RIPEMD128"); + put("Alg.Alias.Mac.OMAC-AES", "OMAC-RIJNDAEL"); + put("Alg.Alias.Mac.OMAC-3DES", "OMAC-3DES"); + put("Alg.Alias.Mac.HmacMD4", "HMAC-MD4"); + put("Alg.Alias.Mac.HmacMD5", "HMAC-MD5"); + put("Alg.Alias.Mac.HmacSHA-1", "HMAC-SHA-1"); + put("Alg.Alias.Mac.HmacSHA1", "HMAC-SHA1"); + put("Alg.Alias.Mac.HmacSHA-160", "HMAC-SHA-160"); + put("Alg.Alias.Mac.HmacSHA160", "HMAC-SHA-160"); + put("Alg.Alias.Mac.HmacSHA-256", "HMAC-SHA-256"); + put("Alg.Alias.Mac.HmacSHA256", "HMAC-SHA-256"); + put("Alg.Alias.Mac.HmacSHA-384", "HMAC-SHA-384"); + put("Alg.Alias.Mac.HmacSHA384", "HMAC-SHA-384"); + put("Alg.Alias.Mac.HmacSHA-512", "HMAC-SHA-512"); + put("Alg.Alias.Mac.HmacSHA512", "HMAC-SHA-512"); + put("Alg.Alias.Mac.HmacRIPEMD128", "HMAC-RIPEMD128"); + put("Alg.Alias.Mac.HmacRIPEMD-128", "HMAC-RIPEMD128"); + put("Alg.Alias.Mac.HmacRIPEMD160", "HMAC-RIPEMD160"); + put("Alg.Alias.Mac.HmacRIPEMD-160", "HMAC-RIPEMD160"); + put("Alg.Alias.Mac.HmacTiger", "HMAC-TIGER"); + put("Alg.Alias.Mac.HmacHaval", "HMAC-HAVAL"); + put("Alg.Alias.Mac.HmacWhirlpool", "HMAC-WHIRLPOOL"); + + // KeyAgreement + put("KeyAgreement.DH", + gnu.javax.crypto.jce.DiffieHellmanImpl.class.getName()); + put("Alg.Alias.KeyAgreement.DiffieHellman", "DH"); + + // Cipher + put("Cipher.RSAES-PKCS1-v1_5", + gnu.javax.crypto.RSACipherImpl.class.getName()); + put("Alg.Alias.Cipher.RSA", "RSAES-PKCS1-v1_5"); + + // SecureRandom + put("SecureRandom.ARCFOUR", + gnu.javax.crypto.jce.prng.ARCFourRandomSpi.class.getName()); + put("SecureRandom.ARCFOUR ImplementedIn", "Software"); + put("SecureRandom.CSPRNG", + gnu.javax.crypto.jce.prng.CSPRNGSpi.class.getName()); + put("SecureRandom.CSPRNG ImplementedIn", "Software"); + put("SecureRandom.ICM", + gnu.javax.crypto.jce.prng.ICMRandomSpi.class.getName()); + put("SecureRandom.ICM ImplementedIn", "Software"); + put("SecureRandom.UMAC-KDF", + gnu.javax.crypto.jce.prng.UMacRandomSpi.class.getName()); + put("SecureRandom.UMAC-KDF ImplementedIn", "Software"); + put("SecureRandom.Fortuna", + gnu.javax.crypto.jce.prng.FortunaImpl.class.getName()); + put("SecureRandom.Fortuna ImplementedIn", "Software"); + + // KeyStore + put("KeyStore.GKR", + gnu.javax.crypto.jce.keyring.GnuKeyring.class.getName()); + put("Alg.Alias.KeyStore.GnuKeyring", "GKR"); + + // KeyPairGenerator --------------------------------------------------- + put("KeyPairGenerator.DH", + gnu.javax.crypto.jce.sig.DHKeyPairGeneratorSpi.class.getName()); + put("KeyPairGenerator.DH KeySize", "512"); + put("KeyPairGenerator.DH ImplementedIn", "Software"); + + put("Alg.Alias.KeyPairGenerator.DiffieHellman", "DH"); + + // KeyFactory --------------------------------------------------------- + put("KeyFactory.DH", + gnu.javax.crypto.jce.sig.DHKeyFactory.class.getName()); + + put("Alg.Alias,KeyFactory.DiffieHellman", "DH"); + + // Algorithm Parameters ----------------------------------------------- + put("AlgorithmParameters.DH", + gnu.javax.crypto.jce.sig.DHParameters.class.getName()); + + put("Alg.Alias.AlgorithmParameters.DiffieHellman", "DH"); + + // Algorithm Parameters Generator ------------------------------------- + put("AlgorithmParameterGenerator.DH", + gnu.javax.crypto.jce.sig.DHParametersGenerator.class.getName()); + + put("Alg.Alias.AlgorithmParameterGenerator.DiffieHellman", "DH"); + + return null; + } + }); + } + + /** + * Returns a {@link Set} of names of symmetric key block cipher algorithms + * available from this {@link Provider}. + * + * @return a {@link Set} of cipher names (Strings). + */ + public static final Set getCipherNames() + { + HashSet s = new HashSet(); + s.addAll(CipherFactory.getNames()); + s.add(Registry.ARCFOUR_PRNG); + return s; + } + + /** + * Returns a {@link Set} of names of MAC algorithms available from this + * {@link Provider}. + * + * @return a {@link Set} of MAC names (Strings). + */ + public static final Set getMacNames() + { + return MacFactory.getNames(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/GnuSasl.java b/libjava/classpath/gnu/javax/crypto/jce/GnuSasl.java new file mode 100644 index 000000000..6ab89e2fa --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/GnuSasl.java @@ -0,0 +1,124 @@ +/* GnuSasl.java -- javax.security.sasl algorithms. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce; + +import gnu.java.security.Registry; +import gnu.javax.crypto.sasl.ClientFactory; +import gnu.javax.crypto.sasl.ServerFactory; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.Provider; +import java.util.Set; + +public final class GnuSasl + extends Provider +{ + public GnuSasl() + { + super(Registry.GNU_SASL, 2.1, "GNU SASL Provider"); + + AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + // SASL Client and Server mechanisms + put("SaslClientFactory.ANONYMOUS", + gnu.javax.crypto.sasl.ClientFactory.class.getName()); + put("SaslClientFactory.PLAIN", + gnu.javax.crypto.sasl.ClientFactory.class.getName()); + put("SaslClientFactory.CRAM-MD5", + gnu.javax.crypto.sasl.ClientFactory.class.getName()); + put("SaslClientFactory.SRP", + gnu.javax.crypto.sasl.ClientFactory.class.getName()); + + put("SaslServerFactory.ANONYMOUS", + gnu.javax.crypto.sasl.ServerFactory.class.getName()); + put("SaslServerFactory.PLAIN", + gnu.javax.crypto.sasl.ServerFactory.class.getName()); + put("SaslServerFactory.CRAM-MD5", + gnu.javax.crypto.sasl.ServerFactory.class.getName()); + put("SaslServerFactory.SRP-MD5", + gnu.javax.crypto.sasl.ServerFactory.class.getName()); + put("SaslServerFactory.SRP-SHA-160", + gnu.javax.crypto.sasl.ServerFactory.class.getName()); + put("SaslServerFactory.SRP-RIPEMD128", + gnu.javax.crypto.sasl.ServerFactory.class.getName()); + put("SaslServerFactory.SRP-RIPEMD160", + gnu.javax.crypto.sasl.ServerFactory.class.getName()); + put("SaslServerFactory.SRP-TIGER", + gnu.javax.crypto.sasl.ServerFactory.class.getName()); + put("SaslServerFactory.SRP-WHIRLPOOL", + gnu.javax.crypto.sasl.ServerFactory.class.getName()); + + put("Alg.Alias.SaslServerFactory.SRP-SHS", "SRP-SHA-160"); + put("Alg.Alias.SaslServerFactory.SRP-SHA", "SRP-SHA-160"); + put("Alg.Alias.SaslServerFactory.SRP-SHA1", "SRP-SHA-160"); + put("Alg.Alias.SaslServerFactory.SRP-SHA-1", "SRP-SHA-160"); + put("Alg.Alias.SaslServerFactory.SRP-SHA160", "SRP-SHA-160"); + put("Alg.Alias.SaslServerFactory.SRP-RIPEMD-128", "SRP-RIPEMD128"); + put("Alg.Alias.SaslServerFactory.SRP-RIPEMD-160", "SRP-RIPEMD160"); + + return null; + } + }); + } + + /** + * Returns a {@link Set} of names of SASL Client mechanisms available from + * this {@link Provider}. + * + * @return a {@link Set} of SASL Client mechanisms (Strings). + */ + public static final Set getSaslClientMechanismNames() + { + return ClientFactory.getNames(); + } + + /** + * Returns a {@link Set} of names of SASL Server mechanisms available from + * this {@link Provider}. + * + * @return a {@link Set} of SASL Server mechanisms (Strings). + */ + public static final Set getSaslServerMechanismNames() + { + return ServerFactory.getNames(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/PBKDF2SecretKeyFactory.java b/libjava/classpath/gnu/javax/crypto/jce/PBKDF2SecretKeyFactory.java new file mode 100644 index 000000000..cda8f34e8 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/PBKDF2SecretKeyFactory.java @@ -0,0 +1,218 @@ +/* PBKDF2SecretKeyFactory.java -- + Copyright (C) 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.crypto.jce; + +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; + +import java.util.HashMap; + +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactorySpi; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.SecretKeySpec; + +import gnu.javax.crypto.prng.IPBE; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.javax.crypto.prng.PRNGFactory; + +public abstract class PBKDF2SecretKeyFactory + extends SecretKeyFactorySpi +{ + protected String macName; + private static final int DEFAULT_ITERATION_COUNT = 1000; + private static final int DEFAULT_KEY_LEN = 32; + + protected PBKDF2SecretKeyFactory(String macName) + { + this.macName = macName; + } + + protected SecretKey engineGenerateSecret(KeySpec spec) + throws InvalidKeySpecException + { + if (! (spec instanceof PBEKeySpec)) + throw new InvalidKeySpecException("not a PBEKeySpec"); + IRandom kdf = PRNGFactory.getInstance("PBKDF2-" + macName); + HashMap attr = new HashMap(); + attr.put(IPBE.PASSWORD, ((PBEKeySpec) spec).getPassword()); + byte[] salt = ((PBEKeySpec) spec).getSalt(); + if (salt == null) + salt = new byte[0]; + attr.put(IPBE.SALT, salt); + int ic = ((PBEKeySpec) spec).getIterationCount(); + if (ic <= 0) + ic = DEFAULT_ITERATION_COUNT; + attr.put(IPBE.ITERATION_COUNT, Integer.valueOf(ic)); + kdf.init(attr); + int len = ((PBEKeySpec) spec).getKeyLength(); + if (len <= 0) + len = DEFAULT_KEY_LEN; + byte[] dk = new byte[len]; + try + { + kdf.nextBytes(dk, 0, len); + } + catch (LimitReachedException lre) + { + throw new IllegalArgumentException(lre.toString()); + } + return new SecretKeySpec(dk, "PBKDF2"); + } + + protected KeySpec engineGetKeySpec(SecretKey key, Class clazz) + throws InvalidKeySpecException + { + throw new InvalidKeySpecException("not supported"); + } + + protected SecretKey engineTranslateKey(SecretKey key) + { + return new SecretKeySpec(key.getEncoded(), key.getAlgorithm()); + } + + public static class HMacHaval + extends PBKDF2SecretKeyFactory + { + public HMacHaval() + { + super("HMAC-HAVAL"); + } + } + + public static class HMacMD2 + extends PBKDF2SecretKeyFactory + { + public HMacMD2() + { + super("HMAC-MD2"); + } + } + + public static class HMacMD4 + extends PBKDF2SecretKeyFactory + { + public HMacMD4() + { + super("HMAC-MD4"); + } + } + + public static class HMacMD5 + extends PBKDF2SecretKeyFactory + { + public HMacMD5() + { + super("HMAC-MD5"); + } + } + + public static class HMacRipeMD128 + extends PBKDF2SecretKeyFactory + { + public HMacRipeMD128() + { + super("HMAC-RIPEMD128"); + } + } + + public static class HMacRipeMD160 + extends PBKDF2SecretKeyFactory + { + public HMacRipeMD160() + { + super("HMAC-RIPEMD160"); + } + } + + public static class HMacSHA1 + extends PBKDF2SecretKeyFactory + { + public HMacSHA1() + { + super("HMAC-SHA1"); + } + } + + public static class HMacSHA256 + extends PBKDF2SecretKeyFactory + { + public HMacSHA256() + { + super("HMAC-SHA256"); + } + } + + public static class HMacSHA384 + extends PBKDF2SecretKeyFactory + { + public HMacSHA384() + { + super("HMAC-SHA384"); + } + } + + public static class HMacSHA512 + extends PBKDF2SecretKeyFactory + { + public HMacSHA512() + { + super("HMAC-SHA512"); + } + } + + public static class HMacTiger + extends PBKDF2SecretKeyFactory + { + public HMacTiger() + { + super("HMAC-TIGER"); + } + } + + public static class HMacWhirlpool + extends PBKDF2SecretKeyFactory + { + public HMacWhirlpool() + { + super("HMAC-WHIRLPOOL"); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/AES128KeyWrapSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/AES128KeyWrapSpi.java new file mode 100644 index 000000000..14ce480ae --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/AES128KeyWrapSpi.java @@ -0,0 +1,54 @@ +/* AESKeyWrapSpi.java -- AES (128-bit key) Key Wrapping Algorithm JCE Adapter + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The JCE Cipher Adapter implementation over the GNU AES Key Wrapping + * Algorithm with a 128-bit key-size. + */ +public final class AES128KeyWrapSpi + extends AESKeyWrapSpi +{ + public AES128KeyWrapSpi() + { + super(Registry.AES128_KWA, 128 / 8, Registry.ECB_MODE); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/AES192KeyWrapSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/AES192KeyWrapSpi.java new file mode 100644 index 000000000..784fc5a15 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/AES192KeyWrapSpi.java @@ -0,0 +1,54 @@ +/* AES192KeyWrapSpi.java -- AES (192-bit key) Key Wrapping Algorithm JCE Adapter + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The JCE Cipher Adapter implementation over the GNU AES Key Wrapping + * Algorithm with a 192-bit key-size. + */ +public final class AES192KeyWrapSpi + extends AESKeyWrapSpi +{ + public AES192KeyWrapSpi() + { + super(Registry.AES192_KWA, 192 / 8, Registry.ECB_MODE); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/AES256KeyWrapSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/AES256KeyWrapSpi.java new file mode 100644 index 000000000..dd7357b0e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/AES256KeyWrapSpi.java @@ -0,0 +1,54 @@ +/* AES256KeyWrapSpi.java -- AES (256-bit key) Key Wrapping Algorithm JCE Adapter + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The JCE Cipher Adapter implementation over the GNU AES Key Wrapping + * Algorithm with a 256-bit key-size. + */ +public final class AES256KeyWrapSpi + extends AESKeyWrapSpi +{ + public AES256KeyWrapSpi() + { + super(Registry.AES256_KWA, 256 / 8, Registry.ECB_MODE); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/AESKeyWrapSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/AESKeyWrapSpi.java new file mode 100644 index 000000000..08f4e7820 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/AESKeyWrapSpi.java @@ -0,0 +1,88 @@ +/* AESKeyWrapSpi.java -- Common AES Key Wrapping Algorithm methods + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +/** + * Base abstract class to group common AES Key Wrapping Algorithm Adapter + * methods. + */ +abstract class AESKeyWrapSpi + extends KeyWrappingAlgorithmAdapter +{ + protected AESKeyWrapSpi(String name, int keySize, String supportedMode) + { + super(name, 16, keySize, supportedMode); + } + + /** + * AES Key Wrapping algorithms operate on an 8-byte block; a block half the + * size of the AES block itself. + *

+ * In wrapping, the number of 8-byte output blocks is ALWAYS one block longer + * than the input. + * + * @param inputLength the size of the plain text. + * @return the size in bytes of n + 1 8-byte blocks where + * n is the smallest number of 8-byte blocks that contain the + * designated number of input bytes. + */ + protected int getOutputSizeForWrap(int inputLength) + { + int n = (inputLength + 7) / 8; + return 8 * (n + 1); + } + + /** + * AES Key Wrapping algorithms operate on an 8-byte block; a block half the + * size of the AES block itself. + *

+ * In unwrapping, the number of 8-byte output blocks is ALWAYS one block + * shorter than the input. + * + * @param inputLength the size of the cipher text. + * @return the size in bytes of n - 1 8-byte blocks where + * n is the smallest number of 8-byte blocks that contain the + * designated number of input bytes. + */ + protected int getOutputSizeForUnwrap(int inputLength) + { + int n = (inputLength + 7) / 8; + return 8 * (n - 1); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/AESSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/AESSpi.java new file mode 100644 index 000000000..4c3e1aecc --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/AESSpi.java @@ -0,0 +1,92 @@ +/* AESSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.cipher; + +import gnu.java.security.Registry; +import gnu.javax.crypto.jce.spec.BlockCipherParameterSpec; + +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; + +/** + * The implementation of the AES Service Provider Interface (SPI) + * adapter. + */ +public final class AESSpi + extends CipherAdapter +{ + public AESSpi() + { + super(Registry.AES_CIPHER, 16); + } + + protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, + SecureRandom random) throws InvalidKeyException, + InvalidAlgorithmParameterException + { + if (params instanceof BlockCipherParameterSpec) + { + if (((BlockCipherParameterSpec) params).getBlockSize() != 16) + throw new InvalidAlgorithmParameterException( + "AES block size must be 16 bytes"); + } + super.engineInit(opmode, key, params, random); + } + + protected void engineInit(int opmode, Key key, AlgorithmParameters params, + SecureRandom random) throws InvalidKeyException, + InvalidAlgorithmParameterException + { + AlgorithmParameterSpec spec = null; + try + { + if (params != null) + spec = params.getParameterSpec(BlockCipherParameterSpec.class); + } + catch (InvalidParameterSpecException ipse) + { + } + engineInit(opmode, key, spec, random); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/ARCFourSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/ARCFourSpi.java new file mode 100644 index 000000000..2e1422e6b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/ARCFourSpi.java @@ -0,0 +1,183 @@ +/* ARCFourSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.cipher; + +import gnu.java.security.Registry; +import gnu.javax.crypto.prng.ARCFour; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.javax.crypto.prng.PRNGFactory; + +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +import java.util.HashMap; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.CipherSpi; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.ShortBufferException; + +/** + * The Service Provider Interface (SPI) for the ARCFOUR stream + * cipher. + */ +public class ARCFourSpi + extends CipherSpi +{ + private IRandom keystream; + + public ARCFourSpi() + { + super(); + keystream = PRNGFactory.getInstance(Registry.ARCFOUR_PRNG); + } + + protected int engineGetBlockSize() + { + return 0; // stream cipher. + } + + protected void engineSetMode(String s) throws NoSuchAlgorithmException + { + // ignored. + } + + protected void engineSetPadding(String s) throws NoSuchPaddingException + { + // ignored. + } + + protected byte[] engineGetIV() + { + return null; + } + + protected int engineGetOutputSize(int in) + { + return in; + } + + protected AlgorithmParameters engineGetParameters() + { + return null; + } + + protected void engineInit(int mode, Key key, SecureRandom r) + throws InvalidKeyException + { + if (mode != Cipher.ENCRYPT_MODE && mode != Cipher.DECRYPT_MODE) + throw new IllegalArgumentException( + "arcfour is for encryption or decryption only"); + if (key == null || ! key.getFormat().equalsIgnoreCase("RAW")) + throw new InvalidKeyException("key must be non-null raw bytes"); + HashMap attrib = new HashMap(); + attrib.put(ARCFour.ARCFOUR_KEY_MATERIAL, key.getEncoded()); + keystream.init(attrib); + } + + protected void engineInit(int mode, Key key, AlgorithmParameterSpec p, + SecureRandom r) throws InvalidKeyException, + InvalidAlgorithmParameterException + { + engineInit(mode, key, r); + } + + protected void engineInit(int mode, Key key, AlgorithmParameters p, + SecureRandom r) throws InvalidKeyException, + InvalidAlgorithmParameterException + { + engineInit(mode, key, r); + } + + protected byte[] engineUpdate(byte[] in, int offset, int length) + { + if (length < 0 || offset < 0 || length + offset > in.length) + throw new ArrayIndexOutOfBoundsException(); + byte[] result = new byte[length]; + try + { + for (int i = 0; i < length; i++) + result[i] = (byte)(in[i + offset] ^ keystream.nextByte()); + } + catch (LimitReachedException wontHappen) + { + } + return result; + } + + protected int engineUpdate(byte[] in, int inOffset, int length, byte[] out, + int outOffset) throws ShortBufferException + { + if (length < 0 || inOffset < 0 || length + inOffset > in.length + || outOffset < 0) + throw new ArrayIndexOutOfBoundsException(); + if (outOffset + length > out.length) + throw new ShortBufferException(); + try + { + for (int i = 0; i < length; i++) + out[i + outOffset] = (byte)(in[i + inOffset] ^ keystream.nextByte()); + } + catch (LimitReachedException wontHappen) + { + } + return length; + } + + protected byte[] engineDoFinal(byte[] in, int offset, int length) + throws IllegalBlockSizeException, BadPaddingException + { + return engineUpdate(in, offset, length); + } + + protected int engineDoFinal(byte[] in, int inOffset, int length, byte[] out, + int outOffset) throws ShortBufferException, + IllegalBlockSizeException, BadPaddingException + { + return engineUpdate(in, inOffset, length, out, outOffset); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/AnubisSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/AnubisSpi.java new file mode 100644 index 000000000..ab0c64867 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/AnubisSpi.java @@ -0,0 +1,54 @@ +/* AnubisSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the Anubis Service Provider Interface + * (SPI) adapter. + */ +public final class AnubisSpi + extends CipherAdapter +{ + public AnubisSpi() + { + super(Registry.ANUBIS_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/BlowfishSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/BlowfishSpi.java new file mode 100644 index 000000000..55d71dbf5 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/BlowfishSpi.java @@ -0,0 +1,54 @@ +/* BlowfishSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the Blowfish Service Provider Interface + * (SPI) adapter. + */ +public final class BlowfishSpi + extends CipherAdapter +{ + public BlowfishSpi() + { + super(Registry.BLOWFISH_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/Cast5Spi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/Cast5Spi.java new file mode 100644 index 000000000..95a663e2f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/Cast5Spi.java @@ -0,0 +1,54 @@ +/* Cast5Spi.java -- + Copyright (C) 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.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the CAST5 (a.k.a. CAST-128) Service + * Provider Interface (SPI) Adapter. + */ +public class Cast5Spi + extends CipherAdapter +{ + public Cast5Spi() + { + super(Registry.CAST5_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/CipherAdapter.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/CipherAdapter.java new file mode 100644 index 000000000..0871c5402 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/CipherAdapter.java @@ -0,0 +1,531 @@ +/* CipherAdapter.java -- + Copyright (C) 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.crypto.jce.cipher; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.jce.spec.BlockCipherParameterSpec; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.mode.ModeFactory; +import gnu.javax.crypto.pad.IPad; +import gnu.javax.crypto.pad.PadFactory; +import gnu.javax.crypto.pad.WrongPaddingException; + +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.CipherSpi; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.ShortBufferException; +import javax.crypto.spec.IvParameterSpec; + +/** + * The implementation of a generic {@link Cipher} Adapter class to wrap + * GNU cipher instances. + *

+ * This class defines the Service Provider Interface (SPI) for + * the {@link Cipher} class, which provides the functionality of symmetric-key + * block ciphers, such as the AES. + *

+ * This base class defines all of the abstract methods in {@link CipherSpi}, + * but does not define the (non-abstract) key wrapping functions that extended + * the base cipher SPI, and these methods thus immediately throw an + * {@link UnsupportedOperationException}. If a cipher implementation provides + * this functionality, or if it in fact accepts parameters other than the key + * and the initialization vector, the subclass should override those methods. + * Otherwise a subclass need only call the {@link #CipherAdapter(String)} + * constructor with the name of the cipher. + */ +class CipherAdapter + extends CipherSpi +{ + /** Our cipher instance. */ + protected IBlockCipher cipher; + /** Our mode instance. */ + protected IMode mode; + /** Our padding instance. */ + protected IPad pad; + /** The current key size. */ + protected int keyLen; + /** Our attributes map. */ + protected Map attributes; + /** An incomplete block. */ + protected byte[] partBlock; + /** The number of bytes in {@link #partBlock}. */ + protected int partLen; + /** The length of blocks we are processing. */ + protected int blockLen; + + /** + * Protected constructor to be called by subclasses. The cipher name argument + * should be the appropriate one listed in {@link Registry}. The basic cipher + * instance is created, along with an instance of the + * {@link gnu.javax.crypto.mode.ECB} mode and no padding. + * + * @param cipherName The cipher to instantiate. + * @param blockLen The block length to use. + */ + protected CipherAdapter(String cipherName, int blockLen) + { + cipher = CipherFactory.getInstance(cipherName); + attributes = new HashMap(); + this.blockLen = blockLen; + mode = ModeFactory.getInstance("ECB", cipher, blockLen); + attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(blockLen)); + } + + /** + * Creates a new cipher adapter with the default block size. + * + * @param cipherName The cipher to instantiate. + */ + protected CipherAdapter(String cipherName) + { + cipher = CipherFactory.getInstance(cipherName); + blockLen = cipher.defaultBlockSize(); + attributes = new HashMap(); + mode = ModeFactory.getInstance("ECB", cipher, blockLen); + attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(blockLen)); + } + + protected void engineSetMode(String modeName) throws NoSuchAlgorithmException + { + if (modeName.length() >= 3 + && modeName.substring(0, 3).equalsIgnoreCase("CFB")) + { + if (modeName.length() > 3) + { + try + { + int bs = Integer.parseInt(modeName.substring(3)); + attributes.put(IMode.MODE_BLOCK_SIZE, Integer.valueOf(bs / 8)); + } + catch (NumberFormatException nfe) + { + throw new NoSuchAlgorithmException(modeName); + } + modeName = "CFB"; + } + } + else + attributes.remove(IMode.MODE_BLOCK_SIZE); + mode = ModeFactory.getInstance(modeName, cipher, blockLen); + if (mode == null) + throw new NoSuchAlgorithmException(modeName); + } + + protected void engineSetPadding(String padName) throws NoSuchPaddingException + { + if (padName.equalsIgnoreCase("NoPadding")) + { + pad = null; + return; + } + pad = PadFactory.getInstance(padName); + if (pad == null) + throw new NoSuchPaddingException(padName); + } + + protected int engineGetBlockSize() + { + if (cipher != null) + return blockLen; + return 0; + } + + protected int engineGetOutputSize(int inputLen) + { + final int blockSize = mode.currentBlockSize(); + return ((inputLen + partLen) / blockSize) * blockSize; + } + + protected byte[] engineGetIV() + { + byte[] iv = (byte[]) attributes.get(IMode.IV); + if (iv == null) + return null; + return (byte[]) iv.clone(); + } + + protected AlgorithmParameters engineGetParameters() + { + byte[] iv = (byte[]) attributes.get(IMode.IV); + int cipherBlockSize = cipher.currentBlockSize(); + BlockCipherParameterSpec spec = new BlockCipherParameterSpec(iv, + cipherBlockSize, + keyLen); + AlgorithmParameters params; + try + { + params = AlgorithmParameters.getInstance("BlockCipherParameters"); + params.init(spec); + } + catch (NoSuchAlgorithmException nsae) + { + return null; + } + catch (InvalidParameterSpecException ipse) + { + return null; + } + return params; + } + + protected void engineInit(int opmode, Key key, SecureRandom random) + throws InvalidKeyException + { + try + { + engineInit(opmode, key, (AlgorithmParameterSpec) null, random); + } + catch (InvalidAlgorithmParameterException e) + { + throw new InvalidKeyException(e.getMessage(), e); + } + } + + /** + * Executes initialization logic after all parameters have been handled by the + * engineInit()s. + * + * @param opmode the desired mode of operation for this instance. + * @param key the key material to use for initialization. + * @param random a source of randmoness to use if/when needed. + * @throws InvalidKeyException if key is invalid or the cipher + * needs extra parameters which can not be derived from + * key; e.g. an IV. + */ + private void engineInitHandler(int opmode, Key key, SecureRandom random) + throws InvalidKeyException + { + switch (opmode) + { + case Cipher.ENCRYPT_MODE: + attributes.put(IMode.STATE, Integer.valueOf(IMode.ENCRYPTION)); + break; + case Cipher.DECRYPT_MODE: + attributes.put(IMode.STATE, Integer.valueOf(IMode.DECRYPTION)); + break; + } + if (! key.getFormat().equalsIgnoreCase("RAW")) + throw new InvalidKeyException("bad key format " + key.getFormat()); + byte[] kb = key.getEncoded(); + int kbLength = kb.length; + if (keyLen == 0) + { + // no key-size given; instead key-material is provided in kb --which + // can be more than what we need. if we don't cull this down to what + // the cipher likes/wants we may get an InvalidKeyException. + // + // try to find the largest key-size value that is less than or equal + // to kbLength + for (Iterator it = cipher.keySizes(); it.hasNext();) + { + int aKeySize = ((Integer) it.next()).intValue(); + if (aKeySize == kbLength) + { + keyLen = aKeySize; + break; + } + else if (aKeySize < kbLength) + keyLen = aKeySize; + else // all remaining key-sizes are longer than kb.length + break; + } + } + if (keyLen == 0) + { + // we were unable to find a key-size, among those advertised by the + // cipher, that is less than or equal to the length of the kb array. + // set keyLen to kbLength. either the cipher implementation will throw + // an InvalidKeyException, or it is implemented in a way which can deal + // with an unsupported key-size. + keyLen = kbLength; + } + if (keyLen < kbLength) + { + byte[] kbb = kb; + kb = new byte[keyLen]; + System.arraycopy(kbb, 0, kb, 0, keyLen); + } + attributes.put(IBlockCipher.KEY_MATERIAL, kb); + reset(); + } + + protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, + SecureRandom random) throws InvalidKeyException, + InvalidAlgorithmParameterException + { + if (params == null) + { + // All cipher modes require parameters (like an IV) except ECB. When + // these cant be derived from the given key then it must be generated + // randomly if in ENCRYPT or WRAP mode. Parameters that have defaults + // for our cipher must be set to these defaults. + if (! mode.name().toLowerCase().startsWith(Registry.ECB_MODE + "(")) + { + switch (opmode) + { + case Cipher.ENCRYPT_MODE: + case Cipher.WRAP_MODE: + byte[] iv = new byte[blockLen]; + random.nextBytes(iv); + attributes.put(IMode.IV, iv); + break; + default: + throw new InvalidAlgorithmParameterException( + "Required algorithm parameters are missing for mode: " + + mode.name()); + } + } + // Add default for block length etc. + blockLen = cipher.defaultBlockSize(); + attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, + Integer.valueOf(blockLen)); + keyLen = 0; + } + else if (params instanceof BlockCipherParameterSpec) + { + BlockCipherParameterSpec bcps = (BlockCipherParameterSpec) params; + blockLen = bcps.getBlockSize(); + attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(blockLen)); + attributes.put(IMode.IV, bcps.getIV()); + keyLen = bcps.getKeySize(); + } + else if (params instanceof IvParameterSpec) + { + // The size of the IV must match the block size + if (((IvParameterSpec) params).getIV().length != cipher.defaultBlockSize()) + { + throw new InvalidAlgorithmParameterException(); + } + + attributes.put(IMode.IV, ((IvParameterSpec) params).getIV()); + blockLen = cipher.defaultBlockSize(); + attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(blockLen)); + keyLen = 0; + } + engineInitHandler(opmode, key, random); + } + + protected void engineInit(int opmode, Key key, AlgorithmParameters params, + SecureRandom random) throws InvalidKeyException, + InvalidAlgorithmParameterException + { + AlgorithmParameterSpec spec = null; + try + { + if (params != null) + spec = params.getParameterSpec(BlockCipherParameterSpec.class); + } + catch (InvalidParameterSpecException ignored) + { + } + engineInit(opmode, key, spec, random); + } + + protected byte[] engineUpdate(byte[] input, int inOff, int inLen) + { + if (inLen == 0) // nothing to process + return new byte[0]; + final int blockSize = mode.currentBlockSize(); + int blockCount = (partLen + inLen) / blockSize; + + // always keep data for unpadding in padded decryption mode; + // might even be a complete block + if (pad != null + && ((Integer) attributes.get(IMode.STATE)).intValue() == IMode.DECRYPTION + && (partLen + inLen) % blockSize == 0) + blockCount--; + + final byte[] out = new byte[blockCount * blockSize]; + try + { + engineUpdate(input, inOff, inLen, out, 0); + } + catch (ShortBufferException x) // should not happen + { + x.printStackTrace(System.err); + } + return out; + } + + protected int engineUpdate(byte[] in, int inOff, int inLen, byte[] out, + int outOff) throws ShortBufferException + { + if (inLen == 0) // nothing to process + return 0; + final int blockSize = mode.currentBlockSize(); + int blockCount = (partLen + inLen) / blockSize; + + // always keep data for unpadding in padded decryption mode; + // might even be a complete block + if (pad != null + && ((Integer) attributes.get(IMode.STATE)).intValue() == IMode.DECRYPTION + && (partLen + inLen) % blockSize == 0) + blockCount--; + + final int result = blockCount * blockSize; + if (result > out.length - outOff) + throw new ShortBufferException(); + if (blockCount == 0) // not enough bytes for even 1 block + { + System.arraycopy(in, inOff, partBlock, partLen, inLen); + partLen += inLen; + return 0; + } + final byte[] buf; + // we have enough bytes for at least 1 block + if (partLen == 0) // if no cached bytes use input + buf = in; + else // prefix input with cached bytes + { + buf = new byte[partLen + inLen]; + System.arraycopy(partBlock, 0, buf, 0, partLen); + if (in != null && inLen > 0) + System.arraycopy(in, inOff, buf, partLen, inLen); + inOff = 0; + } + for (int i = 0; i < blockCount; i++) // update blockCount * blockSize + { + mode.update(buf, inOff, out, outOff); + inOff += blockSize; + outOff += blockSize; + } + partLen += inLen - result; + if (partLen > 0) // cache remaining bytes from buf + System.arraycopy(buf, inOff, partBlock, 0, partLen); + return result; + } + + protected byte[] engineDoFinal(byte[] input, int off, int len) + throws IllegalBlockSizeException, BadPaddingException + { + final byte[] result; + final byte[] buf = engineUpdate(input, off, len); + if (pad != null) + { + switch (((Integer) attributes.get(IMode.STATE)).intValue()) + { + case IMode.ENCRYPTION: + byte[] padding = pad.pad(partBlock, 0, partLen); + byte[] buf2 = engineUpdate(padding, 0, padding.length); + result = new byte[buf.length + buf2.length]; + System.arraycopy(buf, 0, result, 0, buf.length); + System.arraycopy(buf2, 0, result, buf.length, buf2.length); + break; + case IMode.DECRYPTION: + int padLen; + byte[] buf3 = new byte[buf.length + partLen]; + try + { + if (partLen != mode.currentBlockSize()) + throw new WrongPaddingException(); + System.arraycopy(buf, 0, buf3, 0, buf.length); + mode.update(partBlock, 0, buf3, buf.length); + padLen = pad.unpad(buf3, 0, buf3.length); + } + catch (WrongPaddingException wpe) + { + throw new BadPaddingException(wpe.getMessage()); + } + result = new byte[buf3.length - padLen]; + System.arraycopy(buf3, 0, result, 0, result.length); + break; + default: + throw new IllegalStateException(); + } + } + else + { + if (partLen > 0) + throw new IllegalBlockSizeException(partLen + " trailing bytes"); + result = buf; + } + + try + { + reset(); + } + catch (InvalidKeyException ike) + { + // Should not happen; if we initialized it with the current + // parameters before, we should be able to do it again. + throw new Error(ike); + } + return result; + } + + protected int engineDoFinal(byte[] in, int inOff, int inLen, byte[] out, + int outOff) throws BadPaddingException, + IllegalBlockSizeException, ShortBufferException + { + byte[] buf = engineDoFinal(in, inOff, inLen); + if (out.length + outOff < buf.length) + throw new ShortBufferException(); + System.arraycopy(buf, 0, out, outOff, buf.length); + return buf.length; + } + + private void reset() throws InvalidKeyException + { + mode.reset(); + mode.init(attributes); + if (pad != null) + { + pad.reset(); + pad.init(blockLen); + } + partBlock = new byte[blockLen]; + partLen = 0; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/DESSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/DESSpi.java new file mode 100644 index 000000000..0da913a44 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/DESSpi.java @@ -0,0 +1,54 @@ +/* DESSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the DES Service Provider Interface (SPI) + * adapter. + */ +public final class DESSpi + extends CipherAdapter +{ + public DESSpi() + { + super(Registry.DES_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/KeyWrappingAlgorithmAdapter.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/KeyWrappingAlgorithmAdapter.java new file mode 100644 index 000000000..97fdd5331 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/KeyWrappingAlgorithmAdapter.java @@ -0,0 +1,423 @@ +/* KeyWrappingAlgorithmAdapter.java -- Base Adapter for Key Wrapping algorithms + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.javax.crypto.jce.spec.BlockCipherParameterSpec; +import gnu.javax.crypto.kwa.IKeyWrappingAlgorithm; +import gnu.javax.crypto.kwa.KeyUnwrappingException; +import gnu.javax.crypto.kwa.KeyWrappingAlgorithmFactory; + +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.InvalidParameterSpecException; +import java.security.spec.X509EncodedKeySpec; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Logger; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.CipherSpi; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.ShortBufferException; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +/** + * An abstract base class to facilitate implementations of JCE Adapters for + * symmetric key block ciphers capable of providing key-wrapping functionality. + */ +abstract class KeyWrappingAlgorithmAdapter + extends CipherSpi +{ + private static final Logger log = Logger.getLogger(KeyWrappingAlgorithmAdapter.class.getName()); + /** JCE canonical name of a null-padder. */ + private static final String NO_PADDING = "nopadding"; + /** Concrete Key Wrapping Algorithm SPI. */ + protected IKeyWrappingAlgorithm kwAlgorithm; + /** Size in bytes of the padding block to be provided by external padders. */ + protected int kwaBlockSize; + /** KEK size in bytes. */ + protected int kwaKeySize; + /** Name of the supported mode. */ + protected String supportedMode; + /** Operational mode in which this instance was initialised. */ + protected int opmode = -1; + /** Initialisation Vector if/when user wants to override default one. */ + byte[] iv; + + /** + * Creates a new JCE Adapter for the designated Key Wrapping Algorithm name. + * + * @param name the canonical name of the key-wrapping algorithm. + * @param blockSize the block size in bytes of the underlying symmetric-key + * block cipher algorithm. + * @param keySize the allowed size in bytes of the KEK bytes to initialise the + * underlying symmetric-key block cipher algorithm with. + * @param supportedMode canonical name of the block mode the underlying cipher + * is supporting. + */ + protected KeyWrappingAlgorithmAdapter(String name, int blockSize, int keySize, + String supportedMode) + { + super(); + + this.kwAlgorithm = KeyWrappingAlgorithmFactory.getInstance(name); + this.kwaBlockSize = blockSize; + this.kwaKeySize = keySize; + this.supportedMode = supportedMode; + } + + /** + * Wraps the encoded form of a designated {@link Key}. + * + * @param key the key-material to wrap. + * @return the wrapped key. + * @throws InvalidKeyException If the key cannot be wrapped. + */ + protected byte[] engineWrap(Key key) + throws InvalidKeyException, IllegalBlockSizeException + { + byte[] keyMaterial = key.getEncoded(); + byte[] result = kwAlgorithm.wrap(keyMaterial, 0, keyMaterial.length); + return result; + } + + /** + * Unwraps a previously-wrapped key-material. + * + * @param wrappedKey the wrapped key-material to unwrap. + * @param wrappedKeyAlgorithm the canonical name of the algorithm, which the + * unwrapped key-material represents. This name is used to + * instantiate a concrete instance of a {@link Key} for that + * algorithm. For example, if the value of this parameter is + * DSS and the type (the next parameter) is + * {@link Cipher#PUBLIC_KEY} then an attempt to construct a concrete + * instance of a {@link java.security.interfaces.DSAPublicKey}, + * using the unwrapped key material, shall be made. + * @param wrappedKeyType the type of wrapped key-material. MUST be one of + * {@link Cipher#PRIVATE_KEY}, {@link Cipher#PUBLIC_KEY}, or + * {@link Cipher#SECRET_KEY}. + * @return the unwrapped key-material as an instance of {@link Key} or one of + * its subclasses. + * @throws InvalidKeyException If the key cannot be unwrapped, or if + * wrappedKeyType is an inappropriate type for the + * unwrapped key. + * @throws NoSuchAlgorithmException If the wrappedKeyAlgorithm + * is unknown to every currently installed Security Provider. + */ + protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, + int wrappedKeyType) + throws InvalidKeyException, NoSuchAlgorithmException + { + byte[] keyBytes; + try + { + keyBytes = kwAlgorithm.unwrap(wrappedKey, 0, wrappedKey.length); + } + catch (KeyUnwrappingException x) + { + InvalidKeyException y = new InvalidKeyException("engineUnwrap()"); + y.initCause(x); + throw y; + } + Key result; + switch (wrappedKeyType) + { + case Cipher.SECRET_KEY: + result = new SecretKeySpec(keyBytes, wrappedKeyAlgorithm); + break; + case Cipher.PRIVATE_KEY: + case Cipher.PUBLIC_KEY: + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance(wrappedKeyAlgorithm); + try + { + if (wrappedKeyType == Cipher.PRIVATE_KEY) + result = keyFactory.generatePrivate(keySpec); + else + result = keyFactory.generatePublic(keySpec); + } + catch (InvalidKeySpecException x) + { + InvalidKeyException y = new InvalidKeyException("engineUnwrap()"); + y.initCause(x); + throw y; + } + break; + default: + IllegalArgumentException x = new IllegalArgumentException("Invalid 'wrappedKeyType': " + + wrappedKeyType); + InvalidKeyException y = new InvalidKeyException("engineUnwrap()"); + y.initCause(x); + throw y; + } + return result; + } + + protected int engineGetBlockSize() + { + return kwaBlockSize; + } + + protected byte[] engineGetIV() + { + return iv == null ? null : (byte[]) iv.clone(); + } + + protected int engineGetOutputSize(int inputLength) + { + switch (opmode) + { + case Cipher.WRAP_MODE: + return getOutputSizeForWrap(inputLength); + case Cipher.UNWRAP_MODE: + return getOutputSizeForUnwrap(inputLength); + default: + throw new IllegalStateException(); + } + } + + protected AlgorithmParameters engineGetParameters() + { + BlockCipherParameterSpec spec = new BlockCipherParameterSpec(iv, + kwaBlockSize, + kwaKeySize); + AlgorithmParameters result = null; + try + { + result = AlgorithmParameters.getInstance("BlockCipherParameters"); + result.init(spec); + } + catch (NoSuchAlgorithmException x) + { + if (Configuration.DEBUG) + log.fine("Unable to find BlockCipherParameters. Return null"); + } + catch (InvalidParameterSpecException x) + { + if (Configuration.DEBUG) + log.fine("Unable to initialise BlockCipherParameters. Return null"); + } + return result; + } + + protected void engineInit(int opmode, Key key, SecureRandom random) + throws InvalidKeyException + { + checkOpMode(opmode); + byte[] kekBytes = checkAndGetKekBytes(key); + initAlgorithm(opmode, kekBytes, null, random); + } + + protected void engineInit(int opmode, Key key, AlgorithmParameters params, + SecureRandom random) + throws InvalidAlgorithmParameterException, InvalidKeyException + { + AlgorithmParameterSpec spec = null; + try + { + if (params != null) + spec = params.getParameterSpec(BlockCipherParameterSpec.class); + } + catch (InvalidParameterSpecException x) + { + if (Configuration.DEBUG) + log.fine("Unable to translate algorithm parameters into an instance " + + "of BlockCipherParameterSpec. Discard"); + } + engineInit(opmode, key, spec, random); + } + + protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, + SecureRandom random) + throws InvalidAlgorithmParameterException, InvalidKeyException + { + checkOpMode(opmode); + byte[] kekBytes = checkAndGetKekBytes(key); + byte[] ivBytes = null; + if (params instanceof BlockCipherParameterSpec) + ivBytes = ((BlockCipherParameterSpec) params).getIV(); + else if (params instanceof IvParameterSpec) + ivBytes = ((IvParameterSpec) params).getIV(); + + initAlgorithm(opmode, kekBytes, ivBytes, random); + } + + protected void engineSetMode(String mode) throws NoSuchAlgorithmException + { + if (! supportedMode.equalsIgnoreCase(mode)) + throw new UnsupportedOperationException("Only " + supportedMode + + " is supported"); + } + + /** + * NoPadding is the only padding algorithm supported by Key Wrapping Algorithm + * implementations in RI. + */ + protected void engineSetPadding(String padding) throws NoSuchPaddingException + { + if (! NO_PADDING.equalsIgnoreCase(padding)) + throw new UnsupportedOperationException("Only NoPadding is supported"); + } + + protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLength) + { + throw new UnsupportedOperationException(); + } + + protected int engineUpdate(byte[] input, int inputOffset, int inputLength, + byte[] output, int outputOffset) + throws ShortBufferException + { + throw new UnsupportedOperationException(); + } + + protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLength) + throws IllegalBlockSizeException, BadPaddingException + { + throw new UnsupportedOperationException(); + } + + protected int engineDoFinal(byte[] input, int inputOffset, int inputLength, + byte[] output, int outputOffset) + throws IllegalBlockSizeException, BadPaddingException, ShortBufferException + { + throw new UnsupportedOperationException(); + } + + /** + * Return the minimum size in bytes of a place holder large enough to receive + * the cipher text resulting from a wrap method with the designated size of + * the plain text. + *

+ * This default implementation ALWAYS returns the smallest multiple of the + * kwaBlockSize --passed to this method through its + * constructor-- greater than or equal to the designated + * inputLength. + * + * @param inputLength the size of a plain text. + * @return an estimate of the size, in bytes, of the place holder to receive + * the resulting bytes of a wrap method. + */ + protected int getOutputSizeForWrap(int inputLength) + { + return kwaBlockSize * (inputLength + kwaBlockSize - 1) / kwaBlockSize; + } + + /** + * Return the minimum size in bytes of a place holder large enough to receive + * the plain text resulting from an unwrap method with the designated size of + * the cipher text. + *

+ * This default implementation ALWAYS returns the smallest multiple of the + * paddingBlockSize --passed to this method through its + * constructor-- greater than or equal to the designated + * inputLength. + * + * @param inputLength the size of a cipher text. + * @return an estimate of the size, in bytes, of the place holder to receive + * the resulting bytes of an uwrap method. + */ + protected int getOutputSizeForUnwrap(int inputLength) + { + return kwaBlockSize * (inputLength + kwaBlockSize - 1) / kwaBlockSize; + } + + private void checkOpMode(int opmode) + { + switch (opmode) + { + case Cipher.WRAP_MODE: + case Cipher.UNWRAP_MODE: + return; + } + throw new IllegalArgumentException("Unsupported operational mode: " + opmode); + } + + /** + * Returns the key bytes, iff it was in RAW format. + * + * @param key the opaque JCE secret key to use as the KEK. + * @return the bytes of the encoded form of the designated kek, iff it was in + * RAW format. + * @throws InvalidKeyException if the designated key is not in the RAW format. + */ + private byte[] checkAndGetKekBytes(Key key) throws InvalidKeyException + { + if (! Registry.RAW_ENCODING_SHORT_NAME.equalsIgnoreCase(key.getFormat())) + throw new InvalidKeyException("Only RAW key format is supported"); + byte[] result = key.getEncoded(); + int kekSize = result.length; + if (kekSize != kwaKeySize) + throw new InvalidKeyException("Invalid key material size. Expected " + + kwaKeySize + " but found " + kekSize); + return result; + } + + private void initAlgorithm(int opmode, byte[] kek, byte[] ivBytes, + SecureRandom rnd) + throws InvalidKeyException + { + this.opmode = opmode; + Map attributes = new HashMap(); + attributes.put(IKeyWrappingAlgorithm.KEY_ENCRYPTION_KEY_MATERIAL, kek); + if (ivBytes != null) + { + this.iv = (byte[]) ivBytes.clone(); + attributes.put(IKeyWrappingAlgorithm.INITIAL_VALUE, this.iv); + } + else + this.iv = null; + if (rnd != null) + attributes.put(IKeyWrappingAlgorithm.SOURCE_OF_RANDOMNESS, rnd); + + kwAlgorithm.init(attributes); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/KhazadSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/KhazadSpi.java new file mode 100644 index 000000000..df0833fb5 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/KhazadSpi.java @@ -0,0 +1,54 @@ +/* KhazadSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the Khazad Service Provider Interface + * (SPI) adapter. + */ +public final class KhazadSpi + extends CipherAdapter +{ + public KhazadSpi() + { + super(Registry.KHAZAD_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/NullCipherSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/NullCipherSpi.java new file mode 100644 index 000000000..70ff575da --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/NullCipherSpi.java @@ -0,0 +1,54 @@ +/* NullCipherSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the Null cipher Service Provider Interface + * (SPI) adapter. + */ +public final class NullCipherSpi + extends CipherAdapter +{ + public NullCipherSpi() + { + super(Registry.NULL_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/PBES2.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/PBES2.java new file mode 100644 index 000000000..9961c15b1 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/PBES2.java @@ -0,0 +1,1379 @@ +/* PBES2.java -- + Copyright (C) 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.crypto.jce.cipher; + +import gnu.javax.crypto.prng.IPBE; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.javax.crypto.prng.PRNGFactory; + +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.util.HashMap; + +import javax.crypto.interfaces.PBEKey; +import javax.crypto.spec.SecretKeySpec; + +/** + */ +public abstract class PBES2 + extends CipherAdapter +{ + /** The HMac (PRF) algorithm name. */ + protected String macName; + + protected PBES2(String cipherName, int blockLen, String macName) + { + super(cipherName, blockLen); + this.macName = macName; + } + + protected PBES2(String cipherName, String macName) + { + super(cipherName); + this.macName = macName; + } + + protected void engineInit(int opmode, Key key, SecureRandom random) + throws InvalidKeyException + { + if (! (key instanceof PBEKey)) + throw new InvalidKeyException("not a PBE key"); + super.engineInit(opmode, genkey((PBEKey) key), random); + } + + protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, + SecureRandom random) throws InvalidKeyException, + InvalidAlgorithmParameterException + { + if (! (key instanceof PBEKey)) + throw new InvalidKeyException("not a PBE key"); + super.engineInit(opmode, genkey((PBEKey) key), params, random); + } + + protected void engineInit(int opmode, Key key, AlgorithmParameters params, + SecureRandom random) throws InvalidKeyException, + InvalidAlgorithmParameterException + { + if (! (key instanceof PBEKey)) + throw new InvalidKeyException("not a PBE key"); + super.engineInit(opmode, genkey((PBEKey) key), params, random); + } + + private SecretKeySpec genkey(PBEKey key) throws InvalidKeyException + { + IRandom kdf = PRNGFactory.getInstance("PBKDF2-" + macName); + if (kdf == null) + throw new IllegalArgumentException("no such KDF: PBKDF2-" + macName); + HashMap attrib = new HashMap(); + attrib.put(IPBE.ITERATION_COUNT, Integer.valueOf(key.getIterationCount())); + attrib.put(IPBE.PASSWORD, key.getPassword()); + attrib.put(IPBE.SALT, key.getSalt()); + try + { + kdf.init(attrib); + } + catch (IllegalArgumentException iae) + { + throw new InvalidKeyException(iae.toString()); + } + byte[] dk = new byte[mode.defaultKeySize()]; + try + { + kdf.nextBytes(dk, 0, dk.length); + } + catch (LimitReachedException shouldNotHappen) + { + throw new Error(String.valueOf(shouldNotHappen)); + } + return new SecretKeySpec(dk, cipher.name()); + } + + public static class HMacSHA1 + extends PBES2 + { + public HMacSHA1(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-SHA1"); + } + + public HMacSHA1(String cipher) + { + super(cipher, "HMAC-SHA1"); + } + + public static class AES + extends HMacSHA1 + { + public AES() + { + super("AES"); + } + } + + public static class Anubis + extends HMacSHA1 + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish + extends HMacSHA1 + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 + extends HMacSHA1 + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES + extends HMacSHA1 + { + public DES() + { + super("DES"); + } + } + + public static class Khazad + extends HMacSHA1 + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent + extends HMacSHA1 + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square + extends HMacSHA1 + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES + extends HMacSHA1 + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish + extends HMacSHA1 + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacMD5 + extends PBES2 + { + public HMacMD5(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-MD5"); + } + + public HMacMD5(String cipher) + { + super(cipher, "HMAC-MD5"); + } + + public static class AES + extends HMacMD5 + { + public AES() + { + super("AES"); + } + } + + public static class Anubis + extends HMacMD5 + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish + extends HMacMD5 + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 + extends HMacMD5 + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES + extends HMacMD5 + { + public DES() + { + super("DES"); + } + } + + public static class Khazad + extends HMacMD5 + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent + extends HMacMD5 + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square + extends HMacMD5 + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES + extends HMacMD5 + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish + extends HMacMD5 + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacMD2 + extends PBES2 + { + public HMacMD2(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-MD2"); + } + + public HMacMD2(String cipher) + { + super(cipher, "HMAC-MD2"); + } + + public static class AES + extends HMacMD2 + { + public AES() + { + super("AES"); + } + } + + public static class Anubis + extends HMacMD2 + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish + extends HMacMD2 + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 + extends HMacMD2 + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES + extends HMacMD2 + { + public DES() + { + super("DES"); + } + } + + public static class Khazad + extends HMacMD2 + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent + extends HMacMD2 + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square + extends HMacMD2 + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES + extends HMacMD2 + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish + extends HMacMD2 + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacMD4 + extends PBES2 + { + public HMacMD4(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-MD4"); + } + + public HMacMD4(String cipher) + { + super(cipher, "HMAC-MD4"); + } + + public static class AES + extends HMacMD4 + { + public AES() + { + super("AES"); + } + } + + public static class Anubis + extends HMacMD4 + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish + extends HMacMD4 + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 + extends HMacMD4 + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES + extends HMacMD4 + { + public DES() + { + super("DES"); + } + } + + public static class Khazad + extends HMacMD4 + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent + extends HMacMD4 + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square + extends HMacMD4 + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES + extends HMacMD4 + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish + extends HMacMD4 + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacHaval + extends PBES2 + { + public HMacHaval(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-HAVAL"); + } + + public HMacHaval(String cipher) + { + super(cipher, "HMAC-HAVAL"); + } + + public static class AES + extends HMacHaval + { + public AES() + { + super("AES"); + } + } + + public static class Anubis + extends HMacHaval + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish + extends HMacHaval + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 + extends HMacHaval + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES + extends HMacHaval + { + public DES() + { + super("DES"); + } + } + + public static class Khazad + extends HMacHaval + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent + extends HMacHaval + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square + extends HMacHaval + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES + extends HMacHaval + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish + extends HMacHaval + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacRipeMD128 + extends PBES2 + { + public HMacRipeMD128(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-RIPEMD128"); + } + + public HMacRipeMD128(String cipher) + { + super(cipher, "HMAC-RIPEMD128"); + } + + public static class AES + extends HMacRipeMD128 + { + public AES() + { + super("AES"); + } + } + + public static class Anubis + extends HMacRipeMD128 + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish + extends HMacRipeMD128 + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 + extends HMacRipeMD128 + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES + extends HMacRipeMD128 + { + public DES() + { + super("DES"); + } + } + + public static class Khazad + extends HMacRipeMD128 + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent + extends HMacRipeMD128 + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square + extends HMacRipeMD128 + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES + extends HMacRipeMD128 + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish + extends HMacRipeMD128 + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacRipeMD160 + extends PBES2 + { + public HMacRipeMD160(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-RIPEMD160"); + } + + public HMacRipeMD160(String cipher) + { + super(cipher, "HMAC-RIPEMD160"); + } + + public static class AES + extends HMacRipeMD160 + { + public AES() + { + super("AES"); + } + } + + public static class Anubis + extends HMacRipeMD160 + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish + extends HMacRipeMD160 + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 + extends HMacRipeMD160 + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES + extends HMacRipeMD160 + { + public DES() + { + super("DES"); + } + } + + public static class Khazad + extends HMacRipeMD160 + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent + extends HMacRipeMD160 + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square + extends HMacRipeMD160 + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES + extends HMacRipeMD160 + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish + extends HMacRipeMD160 + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacSHA256 + extends PBES2 + { + public HMacSHA256(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-SHA-256"); + } + + public HMacSHA256(String cipher) + { + super(cipher, "HMAC-SHA-256"); + } + + public static class AES + extends HMacSHA256 + { + public AES() + { + super("AES"); + } + } + + public static class Anubis + extends HMacSHA256 + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish + extends HMacSHA256 + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 + extends HMacSHA256 + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES + extends HMacSHA256 + { + public DES() + { + super("DES"); + } + } + + public static class Khazad + extends HMacSHA256 + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent + extends HMacSHA256 + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square + extends HMacSHA256 + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES + extends HMacSHA256 + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish + extends HMacSHA256 + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacSHA384 + extends PBES2 + { + public HMacSHA384(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-SHA-384"); + } + + public HMacSHA384(String cipher) + { + super(cipher, "HMAC-SHA-384"); + } + + public static class AES + extends HMacSHA384 + { + public AES() + { + super("AES"); + } + } + + public static class Anubis + extends HMacSHA384 + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish + extends HMacSHA384 + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 + extends HMacSHA384 + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES + extends HMacSHA384 + { + public DES() + { + super("DES"); + } + } + + public static class Khazad + extends HMacSHA384 + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent + extends HMacSHA384 + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square + extends HMacSHA384 + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES + extends HMacSHA384 + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish + extends HMacSHA384 + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacSHA512 + extends PBES2 + { + public HMacSHA512(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-SHA-512"); + } + + public HMacSHA512(String cipher) + { + super(cipher, "HMAC-SHA-512"); + } + + public static class AES + extends HMacSHA512 + { + public AES() + { + super("AES"); + } + } + + public static class Anubis + extends HMacSHA512 + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish + extends HMacSHA512 + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 + extends HMacSHA512 + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES + extends HMacSHA512 + { + public DES() + { + super("DES"); + } + } + + public static class Khazad + extends HMacSHA512 + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent + extends HMacSHA512 + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square + extends HMacSHA512 + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES + extends HMacSHA512 + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish + extends HMacSHA512 + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacTiger + extends PBES2 + { + public HMacTiger(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-TIGER"); + } + + public HMacTiger(String cipher) + { + super(cipher, "HMAC-TIGER"); + } + + public static class AES + extends HMacTiger + { + public AES() + { + super("AES"); + } + } + + public static class Anubis + extends HMacTiger + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish + extends HMacTiger + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 + extends HMacTiger + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES + extends HMacTiger + { + public DES() + { + super("DES"); + } + } + + public static class Khazad + extends HMacTiger + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent + extends HMacTiger + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square + extends HMacTiger + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES + extends HMacTiger + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish + extends HMacTiger + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacWhirlpool + extends PBES2 + { + public HMacWhirlpool(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-WHIRLPOOL"); + } + + public HMacWhirlpool(String cipher) + { + super(cipher, "HMAC-WHIRLPOOL"); + } + + public static class AES + extends HMacWhirlpool + { + public AES() + { + super("AES"); + } + } + + public static class Anubis + extends HMacWhirlpool + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish + extends HMacWhirlpool + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 + extends HMacWhirlpool + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES + extends HMacWhirlpool + { + public DES() + { + super("DES"); + } + } + + public static class Khazad + extends HMacWhirlpool + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent + extends HMacWhirlpool + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square + extends HMacWhirlpool + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES + extends HMacWhirlpool + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish + extends HMacWhirlpool + { + public Twofish() + { + super("Twofish"); + } + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/RijndaelSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/RijndaelSpi.java new file mode 100644 index 000000000..f25aca028 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/RijndaelSpi.java @@ -0,0 +1,54 @@ +/* RijndaelSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the Rijndael Service Provider Interface + * (SPI) adapter. + */ +public final class RijndaelSpi + extends CipherAdapter +{ + public RijndaelSpi() + { + super(Registry.RIJNDAEL_CIPHER, 16); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/SerpentSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/SerpentSpi.java new file mode 100644 index 000000000..1f17b18c8 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/SerpentSpi.java @@ -0,0 +1,54 @@ +/* SerpentSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the Serpent Service Provider Interface + * (SPI) adapter. + */ +public final class SerpentSpi + extends CipherAdapter +{ + public SerpentSpi() + { + super(Registry.SERPENT_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/SquareSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/SquareSpi.java new file mode 100644 index 000000000..d08aa2cd3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/SquareSpi.java @@ -0,0 +1,54 @@ +/* SquareSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the Square Service Provider Interface + * (SPI) adapter. + */ +public final class SquareSpi + extends CipherAdapter +{ + public SquareSpi() + { + super(Registry.SQUARE_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/TripleDESKeyWrapSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/TripleDESKeyWrapSpi.java new file mode 100644 index 000000000..55087755e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/TripleDESKeyWrapSpi.java @@ -0,0 +1,54 @@ +/* TripleDESKeyWrapSpi.java -- DES-EDE Key Wrapping Algorithm JCE Adapter + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The JCE Cipher Adapter implementation over the GNU TripleDES Key Wrapping + * Algorithm. + */ +public final class TripleDESKeyWrapSpi + extends KeyWrappingAlgorithmAdapter +{ + public TripleDESKeyWrapSpi() + { + super(Registry.TRIPLEDES_KWA, 8, 192 / 8, Registry.CBC_MODE); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/TripleDESSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/TripleDESSpi.java new file mode 100644 index 000000000..c22409020 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/TripleDESSpi.java @@ -0,0 +1,54 @@ +/* TripleDESSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the Triple-DES Service Provider Interface + * (SPI) adapter. + */ +public final class TripleDESSpi + extends CipherAdapter +{ + public TripleDESSpi() + { + super(Registry.TRIPLEDES_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/TwofishSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/TwofishSpi.java new file mode 100644 index 000000000..a1bbe4b71 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/TwofishSpi.java @@ -0,0 +1,54 @@ +/* TwofishSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the Twofish Service Provider Interface + * (SPI) adapter. + */ +public final class TwofishSpi + extends CipherAdapter +{ + public TwofishSpi() + { + super(Registry.TWOFISH_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/AnubisKeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/AnubisKeyGeneratorImpl.java new file mode 100644 index 000000000..a1cc8fd7f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/AnubisKeyGeneratorImpl.java @@ -0,0 +1,50 @@ +/* AnubisKeyGeneratorImpl.java -- Anubis key generator. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.key; + +import gnu.java.security.Registry; + +public class AnubisKeyGeneratorImpl + extends SecretKeyGeneratorImpl +{ + public AnubisKeyGeneratorImpl() + { + super(Registry.ANUBIS_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/AnubisSecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/AnubisSecretKeyFactoryImpl.java new file mode 100644 index 000000000..dc99b332b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/AnubisSecretKeyFactoryImpl.java @@ -0,0 +1,47 @@ +/* AnubisSecretKeyFactoryImpl.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.key; + +public class AnubisSecretKeyFactoryImpl + extends SecretKeyFactoryImpl +{ + public AnubisSecretKeyFactoryImpl() + { + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/BlowfishKeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/BlowfishKeyGeneratorImpl.java new file mode 100644 index 000000000..2297980fb --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/BlowfishKeyGeneratorImpl.java @@ -0,0 +1,50 @@ +/* BlowfishKeyGeneratorImpl.java -- Blowfish key generator. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.key; + +import gnu.java.security.Registry; + +public class BlowfishKeyGeneratorImpl + extends SecretKeyGeneratorImpl +{ + public BlowfishKeyGeneratorImpl() + { + super(Registry.BLOWFISH_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/BlowfishSecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/BlowfishSecretKeyFactoryImpl.java new file mode 100644 index 000000000..8d964bb96 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/BlowfishSecretKeyFactoryImpl.java @@ -0,0 +1,47 @@ +/* BlowfishSecretKeyFactoryImpl.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.key; + +public class BlowfishSecretKeyFactoryImpl + extends SecretKeyFactoryImpl +{ + public BlowfishSecretKeyFactoryImpl() + { + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/Cast5KeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/Cast5KeyGeneratorImpl.java new file mode 100644 index 000000000..b328e48b3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/Cast5KeyGeneratorImpl.java @@ -0,0 +1,50 @@ +/* Cast5KeyGeneratorImpl.java -- CAST-5 key generator. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.key; + +import gnu.java.security.Registry; + +public class Cast5KeyGeneratorImpl + extends SecretKeyGeneratorImpl +{ + public Cast5KeyGeneratorImpl() + { + super(Registry.CAST5_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/Cast5SecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/Cast5SecretKeyFactoryImpl.java new file mode 100644 index 000000000..f2681eda1 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/Cast5SecretKeyFactoryImpl.java @@ -0,0 +1,47 @@ +/* Cast5SecretKeyFactoryImpl.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.key; + +public class Cast5SecretKeyFactoryImpl + extends SecretKeyFactoryImpl +{ + public Cast5SecretKeyFactoryImpl() + { + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/DESKeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/DESKeyGeneratorImpl.java new file mode 100644 index 000000000..2cd29a67f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/DESKeyGeneratorImpl.java @@ -0,0 +1,68 @@ +/* DESKeyGeneratorImpl.java -- DES key generator. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.key; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.DES; + +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +public class DESKeyGeneratorImpl + extends SecretKeyGeneratorImpl +{ + public DESKeyGeneratorImpl() + { + super(Registry.DES_CIPHER); + } + + protected SecretKey engineGenerateKey() + { + if (! init) + throw new IllegalStateException("not initialized"); + byte[] buf = new byte[currentKeySize]; + do + { + random.nextBytes(buf); + } + while (DES.isWeak(buf) || DES.isSemiWeak(buf)); + DES.adjustParity(buf, 0); + return new SecretKeySpec(buf, algorithm); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/DESSecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/DESSecretKeyFactoryImpl.java new file mode 100644 index 000000000..a138e2902 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/DESSecretKeyFactoryImpl.java @@ -0,0 +1,82 @@ +/* DESSecretKeyFactoryImpl.java -- DES key factory. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.key; + +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; + +import javax.crypto.SecretKey; +import javax.crypto.spec.DESKeySpec; +import javax.crypto.spec.SecretKeySpec; + +public class DESSecretKeyFactoryImpl + extends SecretKeyFactoryImpl +{ + + public DESSecretKeyFactoryImpl() + { + } + + protected SecretKey engineGenerateSecret(KeySpec spec) + throws InvalidKeySpecException + { + if (spec instanceof DESKeySpec) + return new SecretKeySpec(((DESKeySpec) spec).getKey(), "DES"); + return super.engineGenerateSecret(spec); + } + + protected KeySpec engineGetKeySpec(SecretKey key, Class spec) + throws InvalidKeySpecException + { + if (spec.isAssignableFrom(DESKeySpec.class)) + try + { + return new DESKeySpec(key.getEncoded()); + } + catch (InvalidKeyException ike) + { + InvalidKeySpecException ikse = new InvalidKeySpecException( + "can't create DES key spec"); + ikse.initCause(ike); + throw ikse; + } + return super.engineGetKeySpec(key, spec); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/DESedeSecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/DESedeSecretKeyFactoryImpl.java new file mode 100644 index 000000000..f380603e4 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/DESedeSecretKeyFactoryImpl.java @@ -0,0 +1,82 @@ +/* DESedeSecretKeyFactoryImpl.java -- DESede key factory. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.key; + +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; + +import javax.crypto.SecretKey; +import javax.crypto.spec.DESedeKeySpec; +import javax.crypto.spec.SecretKeySpec; + +public class DESedeSecretKeyFactoryImpl + extends SecretKeyFactoryImpl +{ + + public DESedeSecretKeyFactoryImpl() + { + } + + protected SecretKey engineGenerateSecret(KeySpec spec) + throws InvalidKeySpecException + { + if (spec instanceof DESedeKeySpec) + return new SecretKeySpec(((DESedeKeySpec) spec).getKey(), "DESede"); + return super.engineGenerateSecret(spec); + } + + protected KeySpec engineGetKeySpec(SecretKey key, Class spec) + throws InvalidKeySpecException + { + if (spec.equals(DESedeKeySpec.class)) + try + { + return new DESedeKeySpec(key.getEncoded()); + } + catch (InvalidKeyException ike) + { + InvalidKeySpecException ikse = new InvalidKeySpecException( + "can't create DESede key spec"); + ikse.initCause(ike); + throw ikse; + } + return super.engineGetKeySpec(key, spec); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/KhazadKeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/KhazadKeyGeneratorImpl.java new file mode 100644 index 000000000..21ae627eb --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/KhazadKeyGeneratorImpl.java @@ -0,0 +1,50 @@ +/* KhazadKeyGeneratorImpl.java -- Khazad key generator. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.key; + +import gnu.java.security.Registry; + +public class KhazadKeyGeneratorImpl + extends SecretKeyGeneratorImpl +{ + public KhazadKeyGeneratorImpl() + { + super(Registry.KHAZAD_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/KhazadSecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/KhazadSecretKeyFactoryImpl.java new file mode 100644 index 000000000..19315d22e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/KhazadSecretKeyFactoryImpl.java @@ -0,0 +1,47 @@ +/* KhazadSecretKeyFactoryImpl.java -- simple byte array-wrapping factory. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.key; + +public class KhazadSecretKeyFactoryImpl + extends SecretKeyFactoryImpl +{ + public KhazadSecretKeyFactoryImpl() + { + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/RijndaelKeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/RijndaelKeyGeneratorImpl.java new file mode 100644 index 000000000..b60f7d6d0 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/RijndaelKeyGeneratorImpl.java @@ -0,0 +1,50 @@ +/* RijndaelKeyGeneratorImpl.java -- Rijndael key generator. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.key; + +import gnu.java.security.Registry; + +public class RijndaelKeyGeneratorImpl + extends SecretKeyGeneratorImpl +{ + public RijndaelKeyGeneratorImpl() + { + super(Registry.RIJNDAEL_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/RijndaelSecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/RijndaelSecretKeyFactoryImpl.java new file mode 100644 index 000000000..f88b07752 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/RijndaelSecretKeyFactoryImpl.java @@ -0,0 +1,47 @@ +/* RijndaelSecretKeyFactoryImpl.java -- simple byte array-wrapping factory. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.key; + +public class RijndaelSecretKeyFactoryImpl + extends SecretKeyFactoryImpl +{ + public RijndaelSecretKeyFactoryImpl() + { + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/SecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/SecretKeyFactoryImpl.java new file mode 100644 index 000000000..4bba171f9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/SecretKeyFactoryImpl.java @@ -0,0 +1,87 @@ +/* SecretKeyFactoryImpl.java -- simple byte array-wrapping factory. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.key; + +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; + +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactorySpi; +import javax.crypto.spec.SecretKeySpec; + +public abstract class SecretKeyFactoryImpl + extends SecretKeyFactorySpi +{ + + protected SecretKeyFactoryImpl() + { + } + + protected SecretKey engineGenerateSecret(KeySpec spec) + throws InvalidKeySpecException + { + if (spec instanceof SecretKeySpec) + return (SecretKey) spec; + throw new InvalidKeySpecException("unknown key spec: " + + spec.getClass().getName()); + } + + protected KeySpec engineGetKeySpec(SecretKey key, Class spec) + throws InvalidKeySpecException + { + if (spec.equals(SecretKeySpec.class)) + { + if (key instanceof SecretKeySpec) + return (KeySpec) key; + else + return new SecretKeySpec(key.getEncoded(), key.getAlgorithm()); + } + throw new InvalidKeySpecException("unsupported key spec: " + spec.getName()); + } + + protected SecretKey engineTranslateKey(SecretKey key) + throws InvalidKeyException + { + if (! "RAW".equals(key.getFormat())) + throw new InvalidKeyException("only raw keys are supported"); + // SecretKeySpec is good enough for our purposes. + return new SecretKeySpec(key.getEncoded(), key.getAlgorithm()); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/SecretKeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/SecretKeyGeneratorImpl.java new file mode 100644 index 000000000..d2acf8716 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/SecretKeyGeneratorImpl.java @@ -0,0 +1,111 @@ +/* SecretKeyGeneratorImpl.java -- symmetric key pair generator. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.key; + +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidParameterException; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import javax.crypto.KeyGeneratorSpi; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +public class SecretKeyGeneratorImpl + extends KeyGeneratorSpi +{ + protected final int defaultKeySize; + protected final List keySizes; + protected final String algorithm; + protected boolean init; + protected int currentKeySize; + protected SecureRandom random; + + protected SecretKeyGeneratorImpl(final String algorithm) + { + this.algorithm = algorithm; + IBlockCipher cipher = CipherFactory.getInstance(algorithm); + if (cipher == null) + throw new IllegalArgumentException("no such cipher: " + algorithm); + defaultKeySize = cipher.defaultKeySize(); + keySizes = new LinkedList(); + for (Iterator it = cipher.keySizes(); it.hasNext();) + keySizes.add(it.next()); + init = false; + } + + protected SecretKey engineGenerateKey() + { + if (! init) + throw new IllegalStateException("not initialized"); + byte[] buf = new byte[currentKeySize]; + random.nextBytes(buf); + return new SecretKeySpec(buf, algorithm); + } + + protected void engineInit(AlgorithmParameterSpec params, SecureRandom random) + throws InvalidAlgorithmParameterException + { + throw new InvalidAlgorithmParameterException( + algorithm + " does not support algorithm paramaters"); + } + + protected void engineInit(int keySize, SecureRandom random) + { + keySize >>>= 3; // Use bytes. + if (! keySizes.contains(Integer.valueOf(keySize))) + throw new InvalidParameterException("unsupported key size: " + keySize + + ", valid sizes are: " + keySizes); + currentKeySize = keySize; + this.random = random; + init = true; + } + + protected void engineInit(SecureRandom random) + { + engineInit(defaultKeySize << 3, random); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/SerpentKeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/SerpentKeyGeneratorImpl.java new file mode 100644 index 000000000..c53190514 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/SerpentKeyGeneratorImpl.java @@ -0,0 +1,50 @@ +/* SerpentKeyGeneratorImpl.java -- Serpent key generator. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.key; + +import gnu.java.security.Registry; + +public class SerpentKeyGeneratorImpl + extends SecretKeyGeneratorImpl +{ + public SerpentKeyGeneratorImpl() + { + super(Registry.SERPENT_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/SerpentSecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/SerpentSecretKeyFactoryImpl.java new file mode 100644 index 000000000..5d5ac88df --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/SerpentSecretKeyFactoryImpl.java @@ -0,0 +1,47 @@ +/* SerpentSecretKeyFactoryImpl.java -- simple byte array-wrapping factory. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.key; + +public class SerpentSecretKeyFactoryImpl + extends SecretKeyFactoryImpl +{ + public SerpentSecretKeyFactoryImpl() + { + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/SquareKeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/SquareKeyGeneratorImpl.java new file mode 100644 index 000000000..3d496e8a9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/SquareKeyGeneratorImpl.java @@ -0,0 +1,50 @@ +/* SquareKeyGeneratorImpl.java -- Square key generator. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.key; + +import gnu.java.security.Registry; + +public class SquareKeyGeneratorImpl + extends SecretKeyGeneratorImpl +{ + public SquareKeyGeneratorImpl() + { + super(Registry.SQUARE_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/SquareSecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/SquareSecretKeyFactoryImpl.java new file mode 100644 index 000000000..f35835912 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/SquareSecretKeyFactoryImpl.java @@ -0,0 +1,47 @@ +/* SquareSecretKeyFactoryImpl.java -- simple byte array-wrapping factory. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.key; + +public class SquareSecretKeyFactoryImpl + extends SecretKeyFactoryImpl +{ + public SquareSecretKeyFactoryImpl() + { + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/TripleDESKeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/TripleDESKeyGeneratorImpl.java new file mode 100644 index 000000000..6fd557ccb --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/TripleDESKeyGeneratorImpl.java @@ -0,0 +1,50 @@ +/* TripleDESKeyGeneratorImpl.java -- TripleDES key generator. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.key; + +import gnu.java.security.Registry; + +public class TripleDESKeyGeneratorImpl + extends SecretKeyGeneratorImpl +{ + public TripleDESKeyGeneratorImpl() + { + super(Registry.TRIPLEDES_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/TwofishKeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/TwofishKeyGeneratorImpl.java new file mode 100644 index 000000000..9dd5a8f30 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/TwofishKeyGeneratorImpl.java @@ -0,0 +1,50 @@ +/* TwofishKeyGeneratorImpl.java -- Twofish key generator. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.key; + +import gnu.java.security.Registry; + +public class TwofishKeyGeneratorImpl + extends SecretKeyGeneratorImpl +{ + public TwofishKeyGeneratorImpl() + { + super(Registry.TWOFISH_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/TwofishSecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/TwofishSecretKeyFactoryImpl.java new file mode 100644 index 000000000..0767d4cac --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/TwofishSecretKeyFactoryImpl.java @@ -0,0 +1,47 @@ +/* TwofishSecretKeyFactoryImpl.java -- simple byte array-wrapping factory. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.key; + +public class TwofishSecretKeyFactoryImpl + extends SecretKeyFactoryImpl +{ + public TwofishSecretKeyFactoryImpl() + { + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/keyring/GnuKeyring.java b/libjava/classpath/gnu/javax/crypto/jce/keyring/GnuKeyring.java new file mode 100644 index 000000000..c30da69a2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/keyring/GnuKeyring.java @@ -0,0 +1,507 @@ +/* GnuKeyring.java -- KeyStore adapter for a pair of private and public Keyrings + Copyright (C) 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.crypto.jce.keyring; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.javax.crypto.keyring.GnuPrivateKeyring; +import gnu.javax.crypto.keyring.GnuPublicKeyring; +import gnu.javax.crypto.keyring.IKeyring; +import gnu.javax.crypto.keyring.IPrivateKeyring; +import gnu.javax.crypto.keyring.IPublicKeyring; +import gnu.javax.crypto.keyring.MalformedKeyringException; +import gnu.javax.crypto.keyring.PrimitiveEntry; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.Key; +import java.security.KeyStoreException; +import java.security.KeyStoreSpi; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.util.Collections; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.logging.Logger; + +import javax.crypto.SecretKey; + +/** + * An Adapter over a pair of one private, and one public keyrings to + * emulate the keystore operations. + */ +public class GnuKeyring + extends KeyStoreSpi +{ + private static final Logger log = Logger.getLogger(GnuKeyring.class.getName()); + private static final String NOT_LOADED = "not loaded"; + + /** TRUE if the keystore is loaded; FALSE otherwise. */ + private boolean loaded; + /** our underlying private keyring. */ + private IPrivateKeyring privateKR; + /** our underlying public keyring. */ + private IPublicKeyring publicKR; + + // default 0-arguments constructor + + public Enumeration engineAliases() + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineAliases"); + ensureLoaded(); + Enumeration result; + if (privateKR == null) + result = Collections.enumeration(Collections.EMPTY_SET); + else + { + Set aliases = new HashSet(); + for (Enumeration e = privateKR.aliases(); e.hasMoreElements();) + { + String alias = (String) e.nextElement(); + if (alias != null) + { + alias = alias.trim(); + if (alias.length() > 0) + { + if (Configuration.DEBUG) + log.fine("Adding alias (from private keyring): " + alias); + aliases.add(alias); + } + } + } + for (Enumeration e = publicKR.aliases(); e.hasMoreElements();) + { + String alias = (String) e.nextElement(); + if (alias != null) + { + alias = alias.trim(); + if (alias.length() > 0) + { + if (Configuration.DEBUG) + log.fine("Adding alias (from public keyring): " + alias); + aliases.add(alias); + } + } + } + if (Configuration.DEBUG) + log.fine("Will enumerate: " + aliases); + result = Collections.enumeration(aliases); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineAliases"); + return result; + } + + public boolean engineContainsAlias(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineContainsAlias", alias); + ensureLoaded(); + boolean inPrivateKR = privateKR.containsAlias(alias); + if (Configuration.DEBUG) + log.fine("inPrivateKR=" + inPrivateKR); + boolean inPublicKR = publicKR.containsAlias(alias); + if (Configuration.DEBUG) + log.fine("inPublicKR=" + inPublicKR); + boolean result = inPrivateKR || inPublicKR; + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineContainsAlias", + Boolean.valueOf(result)); + return result; + } + + public void engineDeleteEntry(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineDeleteEntry", alias); + ensureLoaded(); + if (privateKR.containsAlias(alias)) + privateKR.remove(alias); + else if (publicKR.containsAlias(alias)) + publicKR.remove(alias); + else if (Configuration.DEBUG) + log.fine("Unknwon alias: " + alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineDeleteEntry"); + } + + public Certificate engineGetCertificate(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineGetCertificate", alias); + ensureLoaded(); + Certificate result = publicKR.getCertificate(alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineGetCertificate", result); + return result; + } + + public String engineGetCertificateAlias(Certificate cert) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineGetCertificateAlias", cert); + ensureLoaded(); + String result = null; + for (Enumeration aliases = publicKR.aliases(); aliases.hasMoreElements();) + { + String alias = (String) aliases.nextElement(); + Certificate cert2 = publicKR.getCertificate(alias); + if (cert.equals(cert2)) + { + result = alias; + break; + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineGetCertificateAlias", result); + return result; + } + + public void engineSetCertificateEntry(String alias, Certificate cert) + throws KeyStoreException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineSetCertificateEntry", + new Object[] { alias, cert }); + ensureLoaded(); + if (privateKR.containsAlias(alias)) + throw new KeyStoreException("Alias [" + alias + + "] already exists and DOES NOT identify a " + + "Trusted Certificate Entry"); + if (publicKR.containsCertificate(alias)) + { + if (Configuration.DEBUG) + log.fine("Public keyring already contains Alias [" + alias + + "]. Will remove it"); + publicKR.remove(alias); + } + publicKR.putCertificate(alias, cert); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineSetCertificateEntry"); + } + + public Certificate[] engineGetCertificateChain(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineGetCertificateChain", alias); + ensureLoaded(); + Certificate[] result = privateKR.getCertPath(alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineGetCertificateChain", result); + return result; + } + + public Date engineGetCreationDate(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineGetCreationDate", alias); + ensureLoaded(); + Date result = getCreationDate(alias, privateKR); + if (result == null) + result = getCreationDate(alias, publicKR); + + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineGetCreationDate", result); + return result; + } + + public Key engineGetKey(String alias, char[] password) + throws UnrecoverableKeyException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineGetKey", alias); + ensureLoaded(); + Key result = null; + if (password == null) + { + if (privateKR.containsPublicKey(alias)) + result = privateKR.getPublicKey(alias); + } + else if (privateKR.containsPrivateKey(alias)) + result = privateKR.getPrivateKey(alias, password); + + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineGetKey", + result == null ? "null" : result.getClass().getName()); + return result; + } + + public void engineSetKeyEntry(String alias, Key key, char[] password, + Certificate[] chain) + throws KeyStoreException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineSetKeyEntry", + new Object[] { alias, key.getClass().getName(), chain }); + ensureLoaded(); + if (publicKR.containsAlias(alias)) + throw new KeyStoreException("Alias [" + alias + + "] already exists and DOES NOT identify a " + + "Key Entry"); + if (key instanceof PublicKey) + { + privateKR.remove(alias); + PublicKey pk = (PublicKey) key; + privateKR.putPublicKey(alias, pk); + } + else + { + if (! (key instanceof PrivateKey) && ! (key instanceof SecretKey)) + throw new KeyStoreException("cannot store keys of type " + + key.getClass().getName()); + privateKR.remove(alias); + privateKR.putCertPath(alias, chain); + if (Configuration.DEBUG) + log.fine("About to put private key in keyring..."); + privateKR.putPrivateKey(alias, key, password); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineSetKeyEntry"); + } + + public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain) + throws KeyStoreException + { + KeyStoreException x = new KeyStoreException("method not supported"); + if (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "engineSetKeyEntry(3)", x); + throw x; + } + + public boolean engineIsCertificateEntry(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineIsCertificateEntry", alias); + ensureLoaded(); + boolean result = publicKR.containsCertificate(alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineIsCertificateEntry", + Boolean.valueOf(result)); + return result; + } + + public boolean engineIsKeyEntry(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineIsKeyEntry", alias); + ensureLoaded(); + boolean result = privateKR.containsPublicKey(alias) + || privateKR.containsPrivateKey(alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineIsKeyEntry", + Boolean.valueOf(result)); + return result; + } + + public void engineLoad(InputStream in, char[] password) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineLoad"); + if (in != null) + { + if (! in.markSupported()) + in = new BufferedInputStream(in); + + loadPrivateKeyring(in, password); + loadPublicKeyring(in, password); + } + else + createNewKeyrings(); + + loaded = true; + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineLoad"); + } + + public void engineStore(OutputStream out, char[] password) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineStore"); + ensureLoaded(); + HashMap attr = new HashMap(); + attr.put(IKeyring.KEYRING_DATA_OUT, out); + attr.put(IKeyring.KEYRING_PASSWORD, password); + + privateKR.store(attr); + publicKR.store(attr); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineStore"); + } + + public int engineSize() + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineSize"); + int result = 0; + for (Enumeration e = engineAliases(); e.hasMoreElements(); result++) + e.nextElement(); + + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineSize", Integer.valueOf(result)); + return result; + } + + /** + * Ensure that the underlying keyring pair is loaded. Throw an exception if it + * isn't; otherwise returns silently. + * + * @throws IllegalStateException if the keyring is not loaded. + */ + private void ensureLoaded() + { + if (! loaded) + throw new IllegalStateException(NOT_LOADED); + } + + /** + * Load the private keyring from the designated input stream. + * + * @param in the input stream to process. + * @param password the password protecting the keyring. + * @throws MalformedKeyringException if the keyring is not a private one. + * @throws IOException if an I/O related exception occurs during the process. + */ + private void loadPrivateKeyring(InputStream in, char[] password) + throws MalformedKeyringException, IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "loadPrivateKeyring"); + in.mark(5); + for (int i = 0; i < 4; i++) + if (in.read() != Registry.GKR_MAGIC[i]) + throw new MalformedKeyringException("incorrect magic"); + + int usage = in.read(); + in.reset(); + if (usage != GnuPrivateKeyring.USAGE) + throw new MalformedKeyringException( + "Was expecting a private keyring but got a wrong USAGE: " + + Integer.toBinaryString(usage)); + HashMap attr = new HashMap(); + attr.put(IKeyring.KEYRING_DATA_IN, in); + attr.put(IKeyring.KEYRING_PASSWORD, password); + privateKR = new GnuPrivateKeyring(); + privateKR.load(attr); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "loadPrivateKeyring"); + } + + /** + * Load the public keyring from the designated input stream. + * + * @param in the input stream to process. + * @param password the password protecting the keyring. + * @throws MalformedKeyringException if the keyring is not a public one. + * @throws IOException if an I/O related exception occurs during the process. + */ + private void loadPublicKeyring(InputStream in, char[] password) + throws MalformedKeyringException, IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "loadPublicKeyring"); + in.mark(5); + for (int i = 0; i < 4; i++) + if (in.read() != Registry.GKR_MAGIC[i]) + throw new MalformedKeyringException("incorrect magic"); + + int usage = in.read(); + in.reset(); + if (usage != GnuPublicKeyring.USAGE) + throw new MalformedKeyringException( + "Was expecting a public keyring but got a wrong USAGE: " + + Integer.toBinaryString(usage)); + HashMap attr = new HashMap(); + attr.put(IKeyring.KEYRING_DATA_IN, in); + attr.put(IKeyring.KEYRING_PASSWORD, password); + publicKR = new GnuPublicKeyring(); + publicKR.load(attr); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "loadPublicKeyring"); + } + + /** + * Return the creation date of a named alias in a designated keyring. + * + * @param alias the alias to look for. + * @param keyring the keyring to search. + * @return the creattion date of the entry named alias. Return + * null if alias was not found in + * keyring. + */ + private Date getCreationDate(String alias, IKeyring keyring) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "getCreationDate", + new Object[] { alias, keyring }); + Date result = null; + if (keyring != null) + for (Iterator it = keyring.get(alias).iterator(); it.hasNext();) + { + Object o = it.next(); + if (o instanceof PrimitiveEntry) + { + result = ((PrimitiveEntry) o).getCreationDate(); + break; + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "getCreationDate", result); + return result; + } + + /** Create empty keyrings. */ + private void createNewKeyrings() + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "createNewKeyrings"); + privateKR = new GnuPrivateKeyring("HMAC-SHA-1", 20, "AES", "OFB", 16); + publicKR = new GnuPublicKeyring("HMAC-SHA-1", 20); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "createNewKeyrings"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacHavalSpi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacHavalSpi.java new file mode 100644 index 000000000..fc5f3b578 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacHavalSpi.java @@ -0,0 +1,54 @@ +/* HMacHavalSpi.java -- + Copyright (C) 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.crypto.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the HMAC-HAVAL Service Provider Interface + * (SPI) Adapter. + */ +public class HMacHavalSpi + extends MacAdapter +{ + public HMacHavalSpi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.HAVAL_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD2Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD2Spi.java new file mode 100644 index 000000000..c50feb8cf --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD2Spi.java @@ -0,0 +1,54 @@ +/* HMacMD2Spi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the HMAC-MD2 Service Provider Interface + * (SPI) adapter. + */ +public final class HMacMD2Spi + extends MacAdapter +{ + public HMacMD2Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.MD2_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD4Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD4Spi.java new file mode 100644 index 000000000..c0eae5b22 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD4Spi.java @@ -0,0 +1,54 @@ +/* HMacMD4Spi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the HMAC-MD4 Service Provider Interface + * (SPI) adapter. + */ +public final class HMacMD4Spi + extends MacAdapter +{ + public HMacMD4Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.MD4_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD5Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD5Spi.java new file mode 100644 index 000000000..78e884761 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD5Spi.java @@ -0,0 +1,54 @@ +/* HMacMD5Spi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the HMAC-MD5 Service Provider Interface + * (SPI) adapter. + */ +public final class HMacMD5Spi + extends MacAdapter +{ + public HMacMD5Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.MD5_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacRipeMD128Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacRipeMD128Spi.java new file mode 100644 index 000000000..b5835177c --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacRipeMD128Spi.java @@ -0,0 +1,54 @@ +/* HMacRipeMD128Spi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the HMAC-RIPEMD-128 Service Provider Interface + * (SPI) adapter. + */ +public final class HMacRipeMD128Spi + extends MacAdapter +{ + public HMacRipeMD128Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.RIPEMD128_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacRipeMD160Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacRipeMD160Spi.java new file mode 100644 index 000000000..4d7c6caec --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacRipeMD160Spi.java @@ -0,0 +1,54 @@ +/* HMacRipeMD160Spi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the HMAC-RIPEMD-160 Service Provider Interface + * (SPI) adapter. + */ +public final class HMacRipeMD160Spi + extends MacAdapter +{ + public HMacRipeMD160Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.RIPEMD160_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA160Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA160Spi.java new file mode 100644 index 000000000..1c7c9443d --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA160Spi.java @@ -0,0 +1,54 @@ +/* HMacSHA160Spi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the HMAC-SHA-160 Service Provider Interface + * (SPI) adapter. + */ +public final class HMacSHA160Spi + extends MacAdapter +{ + public HMacSHA160Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.SHA160_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA256Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA256Spi.java new file mode 100644 index 000000000..7d7c91de6 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA256Spi.java @@ -0,0 +1,54 @@ +/* HMacSHA256Spi.java -- + Copyright (C) 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.crypto.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the HMAC-SHA-256 Service Provider Interface + * (SPI) adapter. + */ +public final class HMacSHA256Spi + extends MacAdapter +{ + public HMacSHA256Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.SHA256_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA384Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA384Spi.java new file mode 100644 index 000000000..b66b0f0f3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA384Spi.java @@ -0,0 +1,54 @@ +/* HMacSHA384Spi.java -- + Copyright (C) 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.crypto.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the HMAC-SHA-384 Service Provider Interface + * (SPI) adapter. + */ +public class HMacSHA384Spi + extends MacAdapter +{ + public HMacSHA384Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.SHA384_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA512Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA512Spi.java new file mode 100644 index 000000000..c825a14e9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA512Spi.java @@ -0,0 +1,54 @@ +/* HMacSHA512Spi.java -- + Copyright (C) 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.crypto.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the HMAC-SHA-512 Service Provider Interface + * (SPI) adapter. + */ +public class HMacSHA512Spi + extends MacAdapter +{ + public HMacSHA512Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.SHA512_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacTigerSpi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacTigerSpi.java new file mode 100644 index 000000000..0d979f08f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacTigerSpi.java @@ -0,0 +1,54 @@ +/* HMacTigerSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the Tiger Service Provider Interface + * (SPI) adapter. + */ +public final class HMacTigerSpi + extends MacAdapter +{ + public HMacTigerSpi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.TIGER_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacWhirlpoolSpi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacWhirlpoolSpi.java new file mode 100644 index 000000000..6dde69b7e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacWhirlpoolSpi.java @@ -0,0 +1,54 @@ +/* HMacWhirlpoolSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the HMAC-Whirlpool Service Provider Interface + * (SPI) adapter. + */ +public final class HMacWhirlpoolSpi + extends MacAdapter +{ + public HMacWhirlpoolSpi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.WHIRLPOOL_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/MacAdapter.java b/libjava/classpath/gnu/javax/crypto/jce/mac/MacAdapter.java new file mode 100644 index 000000000..cb3d934fa --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/MacAdapter.java @@ -0,0 +1,136 @@ +/* MacAdapter.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.mac; + +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.spec.AlgorithmParameterSpec; +import java.util.HashMap; +import java.util.Map; +import javax.crypto.MacSpi; + +/** + * The implementation of a generic {@link javax.crypto.Mac} adapter class to + * wrap GNU MAC instances. + *

+ * This class defines the Service Provider Interface (SPI) for + * the {@link javax.crypto.Mac} class, which provides the functionality of a + * message authentication code algorithm, such as the Hashed Message + * Authentication Code (HMAC) algorithms. + */ +class MacAdapter + extends MacSpi + implements Cloneable +{ + /** Our MAC instance. */ + protected IMac mac; + /** Our MAC attributes. */ + protected Map attributes; + + /** + * Creates a new Mac instance for the given name. + * + * @param name The name of the mac to create. + */ + protected MacAdapter(String name) + { + mac = MacFactory.getInstance(name); + attributes = new HashMap(); + } + + /** + * Private constructor for cloning purposes. + * + * @param mac a clone of the internal {@link IMac} instance. + * @param attributes a clone of the current {@link Map} of attributes. + */ + private MacAdapter(IMac mac, Map attributes) + { + super(); + + this.mac = mac; + this.attributes = attributes; + } + + public Object clone() throws CloneNotSupportedException + { + return new MacAdapter((IMac) mac.clone(), new HashMap(attributes)); + } + + protected byte[] engineDoFinal() + { + byte[] result = mac.digest(); + engineReset(); + return result; + } + + protected int engineGetMacLength() + { + return mac.macSize(); + } + + protected void engineInit(Key key, AlgorithmParameterSpec params) + throws InvalidKeyException, InvalidAlgorithmParameterException + { + if (! key.getFormat().equalsIgnoreCase("RAW")) + throw new InvalidKeyException("unknown key format " + key.getFormat()); + attributes.put(IMac.MAC_KEY_MATERIAL, key.getEncoded()); + mac.reset(); + mac.init(attributes); + } + + protected void engineReset() + { + mac.reset(); + } + + protected void engineUpdate(byte b) + { + mac.update(b); + } + + protected void engineUpdate(byte[] in, int off, int len) + { + mac.update(in, off, len); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacAnubisImpl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacAnubisImpl.java new file mode 100644 index 000000000..566e56fd1 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacAnubisImpl.java @@ -0,0 +1,50 @@ +/* OMacAnubisImpl.java -- OMAC-ANUBIS adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.mac; + +import gnu.java.security.Registry; + +public class OMacAnubisImpl + extends MacAdapter +{ + public OMacAnubisImpl() + { + super(Registry.OMAC_PREFIX + Registry.ANUBIS_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacBlowfishImpl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacBlowfishImpl.java new file mode 100644 index 000000000..55768166f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacBlowfishImpl.java @@ -0,0 +1,50 @@ +/* OMacBlowfishImpl.java -- OMAC-BLOWFISH adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.mac; + +import gnu.java.security.Registry; + +public class OMacBlowfishImpl + extends MacAdapter +{ + public OMacBlowfishImpl() + { + super(Registry.OMAC_PREFIX + Registry.BLOWFISH_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacCast5Impl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacCast5Impl.java new file mode 100644 index 000000000..535352c39 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacCast5Impl.java @@ -0,0 +1,50 @@ +/* OMacCast5Impl.java -- OMAC-CAST5 adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.mac; + +import gnu.java.security.Registry; + +public class OMacCast5Impl + extends MacAdapter +{ + public OMacCast5Impl() + { + super(Registry.OMAC_PREFIX + Registry.CAST5_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacDESImpl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacDESImpl.java new file mode 100644 index 000000000..a01c0ac87 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacDESImpl.java @@ -0,0 +1,50 @@ +/* OMacDESImpl.java -- OMAC-DES adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.mac; + +import gnu.java.security.Registry; + +public class OMacDESImpl + extends MacAdapter +{ + public OMacDESImpl() + { + super(Registry.OMAC_PREFIX + Registry.DES_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacImpl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacImpl.java new file mode 100644 index 000000000..960c68aaf --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacImpl.java @@ -0,0 +1,140 @@ +/* OMacImpl.java -- OMAC adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.mac; + +import gnu.java.security.Registry; + +public abstract class OMacImpl + extends MacAdapter +{ + protected OMacImpl(String name) + { + super(Registry.OMAC_PREFIX + name); + } + + public class Anubis + extends OMacImpl + { + public Anubis() + { + super(Registry.ANUBIS_CIPHER); + } + } + + public class Blowfish + extends OMacImpl + { + public Blowfish() + { + super(Registry.BLOWFISH_CIPHER); + } + } + + public class Cast5 + extends OMacImpl + { + public Cast5() + { + super(Registry.CAST5_CIPHER); + } + } + + public class DES + extends OMacImpl + { + public DES() + { + super(Registry.DES_CIPHER); + } + } + + public class Khazad + extends OMacImpl + { + public Khazad() + { + super(Registry.KHAZAD_CIPHER); + } + } + + public class Rijndael + extends OMacImpl + { + public Rijndael() + { + super(Registry.RIJNDAEL_CIPHER); + } + } + + public class Serpent + extends OMacImpl + { + public Serpent() + { + super(Registry.SERPENT_CIPHER); + } + } + + public class Square + extends OMacImpl + { + public Square() + { + super(Registry.SQUARE_CIPHER); + } + } + + public class TripleDES + extends OMacImpl + { + public TripleDES() + { + super(Registry.TRIPLEDES_CIPHER); + } + } + + public class Twofish + extends OMacImpl + { + public Twofish() + { + super(Registry.TWOFISH_CIPHER); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacKhazadImpl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacKhazadImpl.java new file mode 100644 index 000000000..c349f9f5e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacKhazadImpl.java @@ -0,0 +1,50 @@ +/* OMacKhazadImpl.java -- OMAC-KHAZAD adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.mac; + +import gnu.java.security.Registry; + +public class OMacKhazadImpl + extends MacAdapter +{ + public OMacKhazadImpl() + { + super(Registry.OMAC_PREFIX + Registry.KHAZAD_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacRijndaelImpl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacRijndaelImpl.java new file mode 100644 index 000000000..d63b777a3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacRijndaelImpl.java @@ -0,0 +1,50 @@ +/* OMacRijndaelImpl.java -- OMAC-RIJNDAEL adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.mac; + +import gnu.java.security.Registry; + +public class OMacRijndaelImpl + extends MacAdapter +{ + public OMacRijndaelImpl() + { + super(Registry.OMAC_PREFIX + Registry.RIJNDAEL_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacSerpentImpl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacSerpentImpl.java new file mode 100644 index 000000000..5c1b8a9b9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacSerpentImpl.java @@ -0,0 +1,50 @@ +/* OMacSerpentImpl.java -- OMAC-SERPENT adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.mac; + +import gnu.java.security.Registry; + +public class OMacSerpentImpl + extends MacAdapter +{ + public OMacSerpentImpl() + { + super(Registry.OMAC_PREFIX + Registry.SERPENT_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacSquareImpl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacSquareImpl.java new file mode 100644 index 000000000..c9d1b1aca --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacSquareImpl.java @@ -0,0 +1,50 @@ +/* OMacSquareImpl.java -- OMAC-SQUARE adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.mac; + +import gnu.java.security.Registry; + +public class OMacSquareImpl + extends MacAdapter +{ + public OMacSquareImpl() + { + super(Registry.OMAC_PREFIX + Registry.SQUARE_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacTripleDESImpl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacTripleDESImpl.java new file mode 100644 index 000000000..4f58723d3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacTripleDESImpl.java @@ -0,0 +1,50 @@ +/* OMacTripleDESImpl.java -- OMAC-TRIPLEDES adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.mac; + +import gnu.java.security.Registry; + +public class OMacTripleDESImpl + extends MacAdapter +{ + public OMacTripleDESImpl() + { + super(Registry.OMAC_PREFIX + Registry.TRIPLEDES_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacTwofishImpl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacTwofishImpl.java new file mode 100644 index 000000000..4c816a096 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacTwofishImpl.java @@ -0,0 +1,50 @@ +/* OMacTwofishImpl.java -- OMAC-TWOFISH adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.mac; + +import gnu.java.security.Registry; + +public class OMacTwofishImpl + extends MacAdapter +{ + public OMacTwofishImpl() + { + super(Registry.OMAC_PREFIX + Registry.TWOFISH_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/TMMH16Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/TMMH16Spi.java new file mode 100644 index 000000000..d610cc0c2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/TMMH16Spi.java @@ -0,0 +1,81 @@ +/* TMMH16Spi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.mac; + +import gnu.java.security.Registry; +import gnu.javax.crypto.mac.TMMH16; +import gnu.javax.crypto.jce.spec.TMMHParameterSpec; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.spec.AlgorithmParameterSpec; + +/** + * The implementation of the TMMH16 Service Provider Interface + * (SPI) adapter. + */ +public final class TMMH16Spi + extends MacAdapter +{ + public TMMH16Spi() + { + super(Registry.TMMH16); + } + + protected void engineInit(Key key, AlgorithmParameterSpec params) + throws InvalidKeyException, InvalidAlgorithmParameterException + { + if (! (params instanceof TMMHParameterSpec)) + throw new InvalidAlgorithmParameterException(); + TMMHParameterSpec spec = (TMMHParameterSpec) params; + attributes.put(TMMH16.TAG_LENGTH, spec.getTagLength()); + attributes.put(TMMH16.KEYSTREAM, spec.getKeystream()); + attributes.put(TMMH16.PREFIX, spec.getPrefix()); + try + { + mac.reset(); + mac.init(attributes); + } + catch (IllegalArgumentException iae) + { + throw new InvalidAlgorithmParameterException(iae.getMessage()); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/UHash32Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/UHash32Spi.java new file mode 100644 index 000000000..c6784d633 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/UHash32Spi.java @@ -0,0 +1,54 @@ +/* UHash32Spi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the UHash-32 Service Provider Interface + * (SPI) adapter. + */ +public final class UHash32Spi + extends MacAdapter +{ + public UHash32Spi() + { + super(Registry.UHASH32); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/UMac32Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/UMac32Spi.java new file mode 100644 index 000000000..85c859c38 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/UMac32Spi.java @@ -0,0 +1,79 @@ +/* UMac32Spi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.mac; + +import gnu.java.security.Registry; +import gnu.javax.crypto.mac.UMac32; +import gnu.javax.crypto.jce.spec.UMac32ParameterSpec; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.spec.AlgorithmParameterSpec; + +/** + * The implementation of the UMAC-32 Service Provider Interface + * (SPI) adapter. + */ +public final class UMac32Spi + extends MacAdapter +{ + public UMac32Spi() + { + super(Registry.UMAC32); + } + + protected void engineInit(Key key, AlgorithmParameterSpec params) + throws InvalidKeyException, InvalidAlgorithmParameterException + { + if (! (params instanceof UMac32ParameterSpec)) + throw new InvalidAlgorithmParameterException(); + if (params != null) + attributes.put(UMac32.NONCE_MATERIAL, + ((UMac32ParameterSpec) params).getNonce()); + try + { + super.engineInit(key, null); + } + catch (IllegalArgumentException iae) + { + throw new InvalidAlgorithmParameterException(iae.getMessage()); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/params/BlockCipherParameters.java b/libjava/classpath/gnu/javax/crypto/jce/params/BlockCipherParameters.java new file mode 100644 index 000000000..fde83b1f3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/params/BlockCipherParameters.java @@ -0,0 +1,149 @@ +/* BlockCipherParameters.java -- + Copyright (C) 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.crypto.jce.params; + +import gnu.java.security.Configuration; +import gnu.javax.crypto.jce.spec.BlockCipherParameterSpec; + +import java.io.IOException; +import java.math.BigInteger; + +import java.security.AlgorithmParametersSpi; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; +import java.util.logging.Logger; + +import javax.crypto.spec.IvParameterSpec; + +/** + * An implementation of algorithm parameters for the GNU block ciphers. This + * encompasses the cipher's block size, its key size, and an optional + * initialization vector (IV). + */ +public class BlockCipherParameters + extends AlgorithmParametersSpi +{ + private static final Logger log = Logger.getLogger(BlockCipherParameters.class.getName()); + /** The underlying block cipher specification. */ + protected BlockCipherParameterSpec cipherSpec; + private static final String DEFAULT_FORMAT = "ASN.1"; + + /** + * Return these parameters encoded in ASN.1 (DER). + *

+ * For GNU block ciphers we will define these parameters as + *

+   * BlockCipherParameters ::= SEQUENCE {
+   *    blockSize            INTEGER,
+   *    keySize              INTEGER,
+   *    initializationVector OCTET STRING OPTIONAL }
+   * 
+ * + * @return The parameters, encoded an an ASN.1 DER sequence. + * @throws java.io.IOException If encoding these parameters fails. + */ + protected byte[] engineGetEncoded() throws IOException + { + return engineGetEncoded(DEFAULT_FORMAT); + } + + protected byte[] engineGetEncoded(String format) throws IOException + { + if (! format.equalsIgnoreCase(DEFAULT_FORMAT) + && ! format.equalsIgnoreCase("asn1")) + throw new IOException("unknown format \"" + format + "\""); + DERWriter writer = new DERWriter(); + int cipherBlockSize = cipherSpec.getBlockSize(); + int cipherKeySize = cipherSpec.getKeySize(); + byte[] iv = cipherSpec.getIV(); + return writer.joinarrays( + writer.writeBigInteger(BigInteger.valueOf(cipherBlockSize)), + writer.writeBigInteger(BigInteger.valueOf(cipherKeySize)), + (iv != null) ? writer.writeBigInteger(new BigInteger(iv)) + : new byte[0]); + } + + protected void engineInit(AlgorithmParameterSpec spec) + throws InvalidParameterSpecException + { + if (spec instanceof BlockCipherParameterSpec) + cipherSpec = (BlockCipherParameterSpec) spec; + else + throw new InvalidParameterSpecException(); + } + + protected void engineInit(byte[] encoded, String format) throws IOException + { + if (! format.equalsIgnoreCase(DEFAULT_FORMAT) + && ! format.equalsIgnoreCase("ASN1")) + throw new IOException("invalid format: only accepts ASN.1"); + engineInit(encoded); + } + + protected void engineInit(byte[] encoded) throws IOException + { + DERReader reader = new DERReader(encoded); + int bs = reader.getBigInteger().intValue(); + int ks = reader.getBigInteger().intValue(); + byte[] iv = null; + if (reader.hasMorePrimitives()) + iv = reader.getBigInteger().toByteArray(); + cipherSpec = new BlockCipherParameterSpec(iv, bs, ks); + if (Configuration.DEBUG) + log.fine("cipherSpec: " + cipherSpec); + } + + protected AlgorithmParameterSpec engineGetParameterSpec(Class c) + throws InvalidParameterSpecException + { + if (c.isInstance(cipherSpec)) + return cipherSpec; + if (IvParameterSpec.class.isAssignableFrom(c)) + { + IvParameterSpec result = new IvParameterSpec(cipherSpec.getIV()); + return result; + } + throw new InvalidParameterSpecException(); + } + + protected String engineToString() + { + return cipherSpec.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/params/DEREncodingException.java b/libjava/classpath/gnu/javax/crypto/jce/params/DEREncodingException.java new file mode 100644 index 000000000..436f5d4cd --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/params/DEREncodingException.java @@ -0,0 +1,54 @@ +/* DEREncodingException.java -- + Copyright (C) 1999, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.params; + +class DEREncodingException + extends java.io.IOException +{ + + public DEREncodingException() + { + super(); + } + + public DEREncodingException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/params/DERReader.java b/libjava/classpath/gnu/javax/crypto/jce/params/DERReader.java new file mode 100644 index 000000000..9fc1e2cd7 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/params/DERReader.java @@ -0,0 +1,139 @@ +/* DERReader.java -- + Copyright (C) 1999, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.params; + +import java.math.BigInteger; + +class DERReader +{ + byte source[]; + int pos; + static final int UNIVERSAL = 1; + static final int APPLICATION = 2; + static final int CONTEXT_SPECIFIC = 3; + static final int PRIVATE = 4; + + public DERReader() + { + source = null; + pos = 0; + } + + public DERReader(byte source[]) + { + init(source); + } + + public void init(String source) + { + init(source.getBytes()); + } + + public void init(byte source[]) + { + this.source = source; + pos = 0; + } + + public boolean hasMorePrimitives() + { + return pos < source.length; + } + + public BigInteger getBigInteger() throws DEREncodingException + { + return new BigInteger(getPrimitive()); + } + + // Reads Primitive, definite-length method + private byte[] getPrimitive() throws DEREncodingException + { + int tmp = pos; + // Read Identifier + byte identifier = source[tmp++]; + if ((0x20 & identifier) != 0) + throw new DEREncodingException(); + int type = translateLeadIdentifierByte(identifier); + // get tag + int tag = (0x1f & identifier); + // get length + byte len = source[tmp]; // may be length of length parameter + long length = 0x7f & len; + int i; + if ((0x80 & len) != 0) + { + len &= 0x7f; + // get length here + length = 0; + for (i = 0; i < len; i++) + { + tmp++; + length <<= 8; + length += (source[tmp] < 0) ? (256 + source[tmp]) : source[tmp]; + } + tmp++; + } + else + tmp++; + + byte tmpb[] = new byte[(int) length]; + System.arraycopy(source, tmp, tmpb, 0, (int) length); + pos = (int) (tmp + length); + return tmpb; + } + + private int translateLeadIdentifierByte(byte b) + { + if ((0x3f & b) == b) + return UNIVERSAL; + else if ((0x7f & b) == b) + return APPLICATION; + else if ((0xbf & b) == b) + return CONTEXT_SPECIFIC; + else + return PRIVATE; + } + + private int getIdentifier(int tpos) + { + while ((0x80 & source[tpos]) != 0) + tpos++; + return tpos; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/params/DERWriter.java b/libjava/classpath/gnu/javax/crypto/jce/params/DERWriter.java new file mode 100644 index 000000000..7553e20d2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/params/DERWriter.java @@ -0,0 +1,143 @@ +/* DERWriter.java -- + Copyright (C) 1999, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.params; + +import java.math.BigInteger; + +class DERWriter +{ + static final int UNIVERSAL = 1; + static final int APPLICATION = 2; + static final int CONTEXT_SPECIFIC = 3; + static final int PRIVATE = 4; + + public DERWriter() + { + } + + public byte[] writeBigInteger(BigInteger i) + { + return writePrimitive(0x02, + UNIVERSAL, + (int) Math.ceil((double) i.bitLength() / 8), + i.toByteArray()); + } + + private byte[] writePrimitive(int identifier, int identifierencoding, + int length, byte contents[]) + { + return joinarrays(generateIdentifier(identifier, identifierencoding), + generateLength(length), contents); + } + + public byte[] joinarrays(byte a[], byte b[]) + { + byte d[] = new byte[a.length + b.length]; + System.arraycopy(a, 0, d, 0, a.length); + System.arraycopy(b, 0, d, a.length, b.length); + return d; + } + + public byte[] joinarrays(byte a[], byte b[], byte c[]) + { + byte d[] = new byte[a.length + b.length + c.length]; + System.arraycopy(a, 0, d, 0, a.length); + System.arraycopy(b, 0, d, a.length, b.length); + System.arraycopy(c, 0, d, a.length + b.length, c.length); + return d; + } + + private byte[] generateIdentifier(int identifier, int identifierencoding) + { + byte b[]; + if (identifier > 31) + { + int count = (int) (Math.log(identifier) / Math.log(256)); + b = new byte[count + 1]; + b[0] = (byte)(translateLeadIdentifierByte(identifierencoding) | 0x1f); + int i; + for (i = 1; i < (count + 1); i++) + { + b[i] = (byte) (0x7f & (identifier >> (7 * (count - i)))); + b[i] |= 0x80; + } + b[i - 1] ^= 0x80; + return b; + } + else + { + b = new byte[1]; + b[0] = (byte)((translateLeadIdentifierByte(identifierencoding) + | (byte)(identifier & 0x1f)) & 0xdf); + return b; + } + } + + private byte translateLeadIdentifierByte(int b) + { + if (b == UNIVERSAL) + return (byte) 0x3f; + else if (b == APPLICATION) + return (byte) 0x7f; + else if (b == CONTEXT_SPECIFIC) + return (byte) 0xbf; + else + return (byte) 0xC0; + } + + private byte[] generateLength(int length) + { + byte b[]; + if (length > 127) + { + int count = (int) Math.ceil(Math.log(length) / Math.log(256)); + b = new byte[count + 1]; + b[0] = (byte)((count & 0x7f) | 0x80); + for (int i = 1; i < (count + 1); i++) + b[i] = (byte) (length >>> (8 * (count - i))); + return b; + } + else + { + b = new byte[1]; + b[0] = (byte) (length & 0x7f); + return b; + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java b/libjava/classpath/gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java new file mode 100644 index 000000000..3816fb648 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java @@ -0,0 +1,102 @@ +/* ARCFourRandomSpi.java -- + Copyright (C) 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.crypto.jce.prng; + +import gnu.java.security.Registry; + +import gnu.java.security.jce.prng.SecureRandomAdapter; + +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; + +import gnu.javax.crypto.prng.ARCFour; +import gnu.javax.crypto.prng.PRNGFactory; + +import java.security.SecureRandomSpi; + +import java.util.HashMap; + +/** + * Implementation of the Service Provider Interface (SPI) for + * the ARCFOUR keystream generator. + */ +public class ARCFourRandomSpi + extends SecureRandomSpi +{ + /** Our underlying prng instance. */ + private IRandom adaptee; + /** Have we been initialized? */ + private boolean virgin; + + /** + * Default 0-arguments constructor. + */ + public ARCFourRandomSpi() + { + super(); + adaptee = PRNGFactory.getInstance(Registry.ARCFOUR_PRNG); + virgin = true; + } + + public byte[] engineGenerateSeed(int numBytes) + { + return SecureRandomAdapter.getSeed(numBytes); + } + + public void engineNextBytes(byte[] bytes) + { + if (virgin) + this.engineSetSeed(engineGenerateSeed(32)); + try + { + adaptee.nextBytes(bytes, 0, bytes.length); + } + catch (LimitReachedException ignored) + { + } + } + + public void engineSetSeed(byte[] seed) + { + HashMap attributes = new HashMap(); + attributes.put(ARCFour.ARCFOUR_KEY_MATERIAL, seed); + adaptee.init(attributes); + virgin = false; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/prng/CSPRNGSpi.java b/libjava/classpath/gnu/javax/crypto/jce/prng/CSPRNGSpi.java new file mode 100644 index 000000000..9a893af9d --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/prng/CSPRNGSpi.java @@ -0,0 +1,97 @@ +/* CSPRNGSpi.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.prng; + +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.jce.prng.SecureRandomAdapter; +import gnu.javax.crypto.prng.CSPRNG; + +import java.net.MalformedURLException; +import java.security.SecureRandomSpi; + +/** + * The implementation of the continuously-seeded SecureRandom Service + * Provider Interface (SPI) adapter. + */ +public class CSPRNGSpi + extends SecureRandomSpi +{ + private final IRandom adaptee; + private boolean virgin = true; + + public CSPRNGSpi() throws ClassNotFoundException, MalformedURLException, + NumberFormatException + { + super(); + + adaptee = CSPRNG.getSystemInstance(); + } + + protected byte[] engineGenerateSeed(final int numBytes) + { + return SecureRandomAdapter.getSeed(numBytes); + } + + protected void engineNextBytes(final byte[] buffer) + { + if (buffer == null) + throw new NullPointerException(); + if (virgin) + { + engineSetSeed(engineGenerateSeed(32)); + } + try + { + adaptee.nextBytes(buffer, 0, buffer.length); + } + catch (LimitReachedException lre) + { + throw new RuntimeException("random-number generator has been exhausted"); + } + } + + protected void engineSetSeed(final byte[] seed) + { + if (seed == null) + throw new NullPointerException(); + adaptee.addRandomBytes(seed, 0, seed.length); + virgin = false; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/prng/FortunaImpl.java b/libjava/classpath/gnu/javax/crypto/jce/prng/FortunaImpl.java new file mode 100644 index 000000000..d2073b98d --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/prng/FortunaImpl.java @@ -0,0 +1,100 @@ +/* FortunaImpl.java -- Fortuna SecureRandom adapter. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.prng; + +import gnu.java.security.prng.LimitReachedException; + +import gnu.java.security.jce.prng.SecureRandomAdapter; + +import gnu.javax.crypto.prng.Fortuna; + +import java.security.SecureRandomSpi; +import java.util.Collections; + +public final class FortunaImpl + extends SecureRandomSpi +{ + private boolean virgin = true; + private final Fortuna adaptee; + + public FortunaImpl() + { + adaptee = new Fortuna(); + } + + protected void engineSetSeed(byte[] seed) + { + synchronized (adaptee) + { + if (virgin) + { + adaptee.init (Collections.singletonMap (Fortuna.SEED, seed)); + virgin = false; + } + else + { + adaptee.addRandomBytes (seed); + } + } + } + + protected void engineNextBytes(byte[] buffer) + { + synchronized (adaptee) + { + if (virgin) + { + this.engineSetSeed(engineGenerateSeed(32)); + } + try + { + adaptee.nextBytes(buffer); + } + catch (LimitReachedException shouldNotHappen) + { + throw new Error(shouldNotHappen); + } + } + } + + protected byte[] engineGenerateSeed(int numBytes) + { + return SecureRandomAdapter.getSeed(numBytes); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/prng/ICMRandomSpi.java b/libjava/classpath/gnu/javax/crypto/jce/prng/ICMRandomSpi.java new file mode 100644 index 000000000..bbd5d4768 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/prng/ICMRandomSpi.java @@ -0,0 +1,206 @@ +/* ICMRandomSpi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.prng; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.jce.prng.SecureRandomAdapter; +import gnu.java.security.prng.LimitReachedException; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.prng.ICMGenerator; + +import java.math.BigInteger; +import java.security.SecureRandomSpi; +import java.util.HashMap; +import java.util.Random; +import java.util.logging.Logger; + +/** + * An Adapter class around {@link ICMGenerator} to allow using this + * algorithm as a JCE {@link java.security.SecureRandom}. + */ +public class ICMRandomSpi + extends SecureRandomSpi +{ + private static final Logger log = Logger.getLogger(ICMRandomSpi.class.getName()); + /** Class-wide prng to generate random material for the underlying prng. */ + private static final ICMGenerator prng; // blank final + static + { + prng = new ICMGenerator(); + resetLocalPRNG(); + } + + // error messages + private static final String MSG = "Exception while setting up an " + + Registry.ICM_PRNG + " SPI: "; + private static final String RETRY = "Retry..."; + private static final String LIMIT_REACHED_MSG = "Limit reached: "; + private static final String RESEED = "Re-seed..."; + /** Our underlying prng instance. */ + private ICMGenerator adaptee = new ICMGenerator(); + + // default 0-arguments constructor + + private static void resetLocalPRNG() + { + if (Configuration.DEBUG) + log.entering(ICMRandomSpi.class.getName(), "resetLocalPRNG"); + HashMap attributes = new HashMap(); + attributes.put(ICMGenerator.CIPHER, Registry.AES_CIPHER); + byte[] key = new byte[128 / 8]; // AES default key size + Random rand = new Random(System.currentTimeMillis()); + rand.nextBytes(key); + attributes.put(IBlockCipher.KEY_MATERIAL, key); + int aesBlockSize = 128 / 8; // AES block size in bytes + byte[] offset = new byte[aesBlockSize]; + rand.nextBytes(offset); + attributes.put(ICMGenerator.OFFSET, offset); + int ndxLen = 0; // the segment length + // choose a random value between 1 and aesBlockSize / 2 + int limit = aesBlockSize / 2; + while (ndxLen < 1 || ndxLen > limit) + ndxLen = rand.nextInt(limit + 1); + attributes.put(ICMGenerator.SEGMENT_INDEX_LENGTH, Integer.valueOf(ndxLen)); + byte[] index = new byte[ndxLen]; + rand.nextBytes(index); + attributes.put(ICMGenerator.SEGMENT_INDEX, new BigInteger(1, index)); + prng.setup(attributes); + if (Configuration.DEBUG) + log.exiting(ICMRandomSpi.class.getName(), "resetLocalPRNG"); + } + + public byte[] engineGenerateSeed(int numBytes) + { + return SecureRandomAdapter.getSeed(numBytes); + } + + public void engineNextBytes(byte[] bytes) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineNextBytes"); + if (! adaptee.isInitialised()) + this.engineSetSeed(engineGenerateSeed(32)); + while (true) + { + try + { + adaptee.nextBytes(bytes, 0, bytes.length); + break; + } + catch (LimitReachedException x) + { // reseed the generator + if (Configuration.DEBUG) + { + log.fine(LIMIT_REACHED_MSG + String.valueOf(x)); + log.fine(RESEED); + } + resetLocalPRNG(); + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineNextBytes"); + } + + public void engineSetSeed(byte[] seed) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineSetSeed"); + // compute the total number of random bytes required to setup adaptee + int materialLength = 0; + materialLength += 16; // key material size + materialLength += 16; // offset size + materialLength += 8; // index size == half of an AES block + byte[] material = new byte[materialLength]; + // use as much as possible bytes from the seed + int materialOffset = 0; + int materialLeft = material.length; + if (seed.length > 0) + { // copy some bytes into key and update indices + int lenToCopy = Math.min(materialLength, seed.length); + System.arraycopy(seed, 0, material, 0, lenToCopy); + materialOffset += lenToCopy; + materialLeft -= lenToCopy; + } + if (materialOffset > 0) // generate the rest + { + while (true) + { + try + { + prng.nextBytes(material, materialOffset, materialLeft); + break; + } + catch (IllegalStateException x) + { // should not happen + throw new InternalError(MSG + String.valueOf(x)); + } + catch (LimitReachedException x) + { + if (Configuration.DEBUG) + { + log.fine(MSG + String.valueOf(x)); + log.fine(RETRY); + } + } + } + } + // setup the underlying adaptee instance + HashMap attributes = new HashMap(); + // use AES cipher with 128-bit block size + attributes.put(ICMGenerator.CIPHER, Registry.AES_CIPHER); + // use an index the size of quarter of an AES block + attributes.put(ICMGenerator.SEGMENT_INDEX_LENGTH, Integer.valueOf(4)); + // specify the key + byte[] key = new byte[16]; + System.arraycopy(material, 0, key, 0, 16); + attributes.put(IBlockCipher.KEY_MATERIAL, key); + // specify the offset + byte[] offset = new byte[16]; + System.arraycopy(material, 16, offset, 0, 16); + attributes.put(ICMGenerator.OFFSET, offset); + // specify the index + byte[] index = new byte[4]; + System.arraycopy(material, 32, index, 0, 4); + attributes.put(ICMGenerator.SEGMENT_INDEX, new BigInteger(1, index)); + adaptee.init(attributes); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineSetSeed"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/prng/UMacRandomSpi.java b/libjava/classpath/gnu/javax/crypto/jce/prng/UMacRandomSpi.java new file mode 100644 index 000000000..910e65c70 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/prng/UMacRandomSpi.java @@ -0,0 +1,166 @@ +/* UMacRandomSpi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.prng; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.jce.prng.SecureRandomAdapter; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.prng.UMacGenerator; + +import java.security.SecureRandomSpi; +import java.util.HashMap; +import java.util.Random; +import java.util.logging.Logger; + +/** + * An Adapter class around {@link UMacGenerator} to allow using this + * algorithm as a JCE {@link java.security.SecureRandom}. + */ +public class UMacRandomSpi + extends SecureRandomSpi +{ + private static final Logger log = Logger.getLogger(UMacRandomSpi.class.getName()); + + /** Class-wide prng to generate random material for the underlying prng. */ + private static final UMacGenerator prng; // blank final + static + { + prng = new UMacGenerator(); + resetLocalPRNG(); + } + // error messages + private static final String MSG = "Exception while setting up a " + + Registry.UMAC_PRNG + " SPI: "; + private static final String RETRY = "Retry..."; + /** Our underlying prng instance. */ + private UMacGenerator adaptee = new UMacGenerator(); + + // default 0-arguments constructor + + private static void resetLocalPRNG() + { + HashMap attributes = new HashMap(); + attributes.put(UMacGenerator.CIPHER, Registry.AES_CIPHER); + byte[] key = new byte[128 / 8]; // AES default key size + Random rand = new Random(System.currentTimeMillis()); + rand.nextBytes(key); + attributes.put(IBlockCipher.KEY_MATERIAL, key); + int index = rand.nextInt() & 0xFF; + attributes.put(UMacGenerator.INDEX, Integer.valueOf(index)); + prng.setup(attributes); + } + + public byte[] engineGenerateSeed(int numBytes) + { + return SecureRandomAdapter.getSeed(numBytes); + } + + public void engineNextBytes(byte[] bytes) + { + if (! adaptee.isInitialised()) + engineSetSeed(engineGenerateSeed(32)); + while (true) + { + try + { + adaptee.nextBytes(bytes, 0, bytes.length); + break; + } + catch (LimitReachedException x) + { // reseed the generator + resetLocalPRNG(); + } + } + } + + public void engineSetSeed(byte[] seed) + { + // compute the total number of random bytes required to setup adaptee + int materialLength = 0; + materialLength += 16; // key material size + materialLength++; // index size + byte[] material = new byte[materialLength]; + // use as much as possible bytes from the seed + int materialOffset = 0; + int materialLeft = material.length; + if (seed.length > 0) + { // copy some bytes into key and update indices + int lenToCopy = Math.min(materialLength, seed.length); + System.arraycopy(seed, 0, material, 0, lenToCopy); + materialOffset += lenToCopy; + materialLeft -= lenToCopy; + } + if (materialOffset > 0) // generate the rest + { + while (true) + { + try + { + prng.nextBytes(material, materialOffset, materialLeft); + break; + } + catch (IllegalStateException x) // should not happen + { + throw new InternalError(MSG + String.valueOf(x)); + } + catch (LimitReachedException x) + { + if (Configuration.DEBUG) + { + log.fine(MSG + String.valueOf(x)); + log.fine(RETRY); + } + } + } + } + // setup the underlying adaptee instance + HashMap attributes = new HashMap(); + // use AES cipher with 128-bit block size + attributes.put(UMacGenerator.CIPHER, Registry.AES_CIPHER); + // specify the key + byte[] key = new byte[16]; + System.arraycopy(material, 0, key, 0, 16); + attributes.put(IBlockCipher.KEY_MATERIAL, key); + // use a 1-byte index + attributes.put(UMacGenerator.INDEX, Integer.valueOf(material[16] & 0xFF)); + adaptee.init(attributes); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/sig/DHKeyFactory.java b/libjava/classpath/gnu/javax/crypto/jce/sig/DHKeyFactory.java new file mode 100644 index 000000000..98b265dd3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/sig/DHKeyFactory.java @@ -0,0 +1,219 @@ +/* DHKeyFactory.java -- DH key-factory JCE Adapter + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.sig; + +import gnu.java.security.Registry; +import gnu.javax.crypto.key.dh.DHKeyPairPKCS8Codec; +import gnu.javax.crypto.key.dh.DHKeyPairX509Codec; +import gnu.javax.crypto.key.dh.GnuDHPrivateKey; +import gnu.javax.crypto.key.dh.GnuDHPublicKey; + +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactorySpi; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +import javax.crypto.interfaces.DHPrivateKey; +import javax.crypto.interfaces.DHPublicKey; +import javax.crypto.spec.DHPrivateKeySpec; +import javax.crypto.spec.DHPublicKeySpec; + +/** + * Implementation of a JCE Adapter for DH a key-factory. + */ +public class DHKeyFactory + extends KeyFactorySpi +{ + // implicit 0-arguments constructor + + protected PublicKey engineGeneratePublic(KeySpec keySpec) + throws InvalidKeySpecException + { + if (keySpec instanceof DHPublicKeySpec) + { + DHPublicKeySpec spec = (DHPublicKeySpec) keySpec; + BigInteger p = spec.getP(); + BigInteger g = spec.getG(); + BigInteger y = spec.getY(); + return new GnuDHPublicKey(Registry.X509_ENCODING_ID, null, p, g, y); + } + if (keySpec instanceof X509EncodedKeySpec) + { + X509EncodedKeySpec spec = (X509EncodedKeySpec) keySpec; + byte[] encoded = spec.getEncoded(); + PublicKey result; + try + { + result = new DHKeyPairX509Codec().decodePublicKey(encoded); + return result; + } + catch (RuntimeException x) + { + InvalidKeySpecException y = new InvalidKeySpecException(); + y.initCause(x); + throw y; + } + } + throw new InvalidKeySpecException("Unsupported (public) key specification"); + } + + protected PrivateKey engineGeneratePrivate(KeySpec keySpec) + throws InvalidKeySpecException + { + if (keySpec instanceof DHPrivateKeySpec) + { + DHPrivateKeySpec spec = (DHPrivateKeySpec) keySpec; + BigInteger p = spec.getP(); + BigInteger g = spec.getG(); + BigInteger x = spec.getX(); + return new GnuDHPrivateKey(Registry.PKCS8_ENCODING_ID, null, p, g, x); + } + if (keySpec instanceof PKCS8EncodedKeySpec) + { + PKCS8EncodedKeySpec spec = (PKCS8EncodedKeySpec) keySpec; + byte[] encoded = spec.getEncoded(); + PrivateKey result; + try + { + result = new DHKeyPairPKCS8Codec().decodePrivateKey(encoded); + return result; + } + catch (RuntimeException x) + { + InvalidKeySpecException y = new InvalidKeySpecException(); + y.initCause(x); + throw y; + } + } + throw new InvalidKeySpecException("Unsupported (private) key specification"); + } + + protected KeySpec engineGetKeySpec(Key key, Class keySpec) + throws InvalidKeySpecException + { + if (key instanceof DHPublicKey) + { + if (keySpec.isAssignableFrom(DHPublicKeySpec.class)) + { + DHPublicKey dssKey = (DHPublicKey) key; + BigInteger p = dssKey.getParams().getP(); + BigInteger g = dssKey.getParams().getG(); + BigInteger y = dssKey.getY(); + return new DHPublicKeySpec(y, p, g); + } + if (keySpec.isAssignableFrom(X509EncodedKeySpec.class)) + { + if (key instanceof GnuDHPublicKey) + { + GnuDHPublicKey dhKey = (GnuDHPublicKey) key; + byte[] encoded = dhKey.getEncoded(Registry.X509_ENCODING_ID); + return new X509EncodedKeySpec(encoded); + } + if (Registry.X509_ENCODING_SORT_NAME.equalsIgnoreCase(key.getFormat())) + { + byte[] encoded = key.getEncoded(); + return new X509EncodedKeySpec(encoded); + } + throw new InvalidKeySpecException( + "Wrong key type or unsupported (public) key specification"); + } + throw new InvalidKeySpecException("Unsupported (public) key specification"); + } + if (key instanceof DHPrivateKey) + { + if (keySpec.isAssignableFrom(DHPrivateKeySpec.class)) + { + DHPrivateKey dhKey = (DHPrivateKey) key; + BigInteger p = dhKey.getParams().getP(); + BigInteger g = dhKey.getParams().getG(); + BigInteger x = dhKey.getX(); + return new DHPrivateKeySpec(x, p, g); + } + if (keySpec.isAssignableFrom(PKCS8EncodedKeySpec.class)) + { + if (key instanceof GnuDHPrivateKey) + { + GnuDHPrivateKey dhKey = (GnuDHPrivateKey) key; + byte[] encoded = dhKey.getEncoded(Registry.PKCS8_ENCODING_ID); + return new PKCS8EncodedKeySpec(encoded); + } + if (Registry.PKCS8_ENCODING_SHORT_NAME.equalsIgnoreCase(key.getFormat())) + { + byte[] encoded = key.getEncoded(); + return new PKCS8EncodedKeySpec(encoded); + } + throw new InvalidKeySpecException( + "Wrong key type or unsupported (private) key specification"); + } + throw new InvalidKeySpecException( + "Unsupported (private) key specification"); + } + throw new InvalidKeySpecException( + "Wrong key type or unsupported key specification"); + } + + protected Key engineTranslateKey(Key key) throws InvalidKeyException + { + if ((key instanceof GnuDHPublicKey) || (key instanceof GnuDHPrivateKey)) + return key; + if (key instanceof DHPublicKey) + { + DHPublicKey dsaKey = (DHPublicKey) key; + BigInteger p = dsaKey.getParams().getP(); + BigInteger g = dsaKey.getParams().getG(); + BigInteger y = dsaKey.getY(); + return new GnuDHPublicKey(Registry.X509_ENCODING_ID, null, p, g, y); + } + if (key instanceof DHPrivateKey) + { + DHPrivateKey dsaKey = (DHPrivateKey) key; + BigInteger p = dsaKey.getParams().getP(); + BigInteger g = dsaKey.getParams().getG(); + BigInteger x = dsaKey.getX(); + return new GnuDHPrivateKey(Registry.PKCS8_ENCODING_ID, null, p, g, x); + } + throw new InvalidKeyException("Wrong key type"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/sig/DHKeyPairGeneratorSpi.java b/libjava/classpath/gnu/javax/crypto/jce/sig/DHKeyPairGeneratorSpi.java new file mode 100644 index 000000000..e26f07124 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/sig/DHKeyPairGeneratorSpi.java @@ -0,0 +1,93 @@ +/* DHKeyPairGeneratorSpi.java -- DH key-pair generator JCE Adapter + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.sig; + +import java.security.InvalidAlgorithmParameterException; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.util.HashMap; + +import javax.crypto.spec.DHGenParameterSpec; +import javax.crypto.spec.DHParameterSpec; + +import gnu.java.security.Registry; +import gnu.java.security.jce.sig.KeyPairGeneratorAdapter; +import gnu.javax.crypto.key.dh.GnuDHKeyPairGenerator; + +public class DHKeyPairGeneratorSpi + extends KeyPairGeneratorAdapter +{ + public DHKeyPairGeneratorSpi() + { + super(Registry.DH_KPG); + } + + public void initialize(int keysize, SecureRandom random) + { + HashMap attributes = new HashMap(); + attributes.put(GnuDHKeyPairGenerator.PRIME_SIZE, Integer.valueOf(keysize)); + if (random != null) + attributes.put(GnuDHKeyPairGenerator.SOURCE_OF_RANDOMNESS, random); + + attributes.put(GnuDHKeyPairGenerator.PREFERRED_ENCODING_FORMAT, + Integer.valueOf(Registry.ASN1_ENCODING_ID)); + adaptee.setup(attributes); + } + + public void initialize(AlgorithmParameterSpec params, SecureRandom random) + throws InvalidAlgorithmParameterException + { + HashMap attributes = new HashMap(); + if (params != null) + { + if (! (params instanceof DHGenParameterSpec) && + ! (params instanceof DHParameterSpec)) + throw new InvalidAlgorithmParameterException("params"); + + attributes.put(GnuDHKeyPairGenerator.DH_PARAMETERS, params); + } + + if (random != null) + attributes.put(GnuDHKeyPairGenerator.SOURCE_OF_RANDOMNESS, random); + + attributes.put(GnuDHKeyPairGenerator.PREFERRED_ENCODING_FORMAT, + Integer.valueOf(Registry.ASN1_ENCODING_ID)); + adaptee.setup(attributes); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/sig/DHParameters.java b/libjava/classpath/gnu/javax/crypto/jce/sig/DHParameters.java new file mode 100644 index 000000000..cc656d2c8 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/sig/DHParameters.java @@ -0,0 +1,222 @@ +/* DHParameters.java -- DH parameters DAO + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.sig; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.Registry; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.der.DERWriter; +import gnu.java.security.util.DerUtil; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.AlgorithmParametersSpi; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; +import java.util.ArrayList; + +import javax.crypto.spec.DHGenParameterSpec; +import javax.crypto.spec.DHParameterSpec; + +/** + * A JCE-specific Data Access Object (DAO) for DH parameters. + */ +public class DHParameters + extends AlgorithmParametersSpi +{ + /** The prime public modulus. */ + private BigInteger p; + + /** The generator. */ + private BigInteger g; + + /** A prime factor of p-1. */ + private BigInteger q; + + /** The (private) random exponent's size (in bits). */ + private int l; + + // default 0-arguments constructor + + protected void engineInit(AlgorithmParameterSpec spec) + throws InvalidParameterSpecException + { + if (! (spec instanceof DHParameterSpec)) + throw new InvalidParameterSpecException("Wrong AlgorithmParameterSpec type: " + + spec.getClass().getName()); + DHParameterSpec dhSpec = (DHParameterSpec) spec; + p = dhSpec.getP(); + g = dhSpec.getG(); + l = dhSpec.getL(); + } + + /** + * Decodes the set of DH parameters as per RFC-2459; i.e. the DER-encoded + * form of the following ASN.1 construct: + * + *
+   *   DhParams ::= SEQUENCE {
+   *     p  INTEGER, -- odd prime, p=jq +1
+   *     g  INTEGER, -- generator, g
+   *     q  INTEGER  -- factor of p-1
+   *   }
+   * 
+ */ + protected void engineInit(byte[] params) throws IOException + { + DERReader der = new DERReader(params); + + DERValue derParams = der.read(); + DerUtil.checkIsConstructed(derParams, "Wrong DH Parameters field"); + + DERValue val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong P field"); + p = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong G field"); + g = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong Q field"); + q = (BigInteger) val.getValue(); + l = q.bitLength(); + } + + protected void engineInit(byte[] params, String format) throws IOException + { + if (format != null) + { + format = format.trim(); + if (format.length() == 0) + throw new IOException("Format MUST NOT be an empty string"); + + if (! format.equalsIgnoreCase(Registry.ASN1_ENCODING_SHORT_NAME)) + throw new IOException("Unknown or unsupported format: " + format); + } + + engineInit(params); + } + + protected AlgorithmParameterSpec engineGetParameterSpec(Class paramSpec) + throws InvalidParameterSpecException + { + if (paramSpec.isAssignableFrom(DHParameterSpec.class)) + return new DHParameterSpec(p, g, l); + + if (paramSpec.isAssignableFrom(DHGenParameterSpec.class)) + return new DHGenParameterSpec(p.bitLength(), l); + + throw new InvalidParameterSpecException("Wrong AlgorithmParameterSpec type: " + + paramSpec.getName()); + } + + /** + * Encodes the set of DH parameters as per RFC-2459; i.e. as the DER-encoded + * form of the following ASN.1 construct: + * + *
+   *   DhParams ::= SEQUENCE {
+   *     p  INTEGER, -- odd prime, p=jq +1
+   *     g  INTEGER, -- generator, g
+   *     q  INTEGER  -- factor of p-1
+   *   }
+   * 
+ */ + protected byte[] engineGetEncoded() throws IOException + { + DERValue derP = new DERValue(DER.INTEGER, p); + DERValue derG = new DERValue(DER.INTEGER, g); + DERValue derQ = new DERValue(DER.INTEGER, q); + + ArrayList params = new ArrayList(3); + params.add(derP); + params.add(derG); + params.add(derQ); + DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DERWriter.write(baos, derParams); + byte[] result = baos.toByteArray(); + + return result; + } + + protected byte[] engineGetEncoded(String format) throws IOException + { + if (format != null) + { + format = format.trim(); + if (format.length() == 0) + throw new IOException("Format MUST NOT be an empty string"); + + if (! format.equalsIgnoreCase(Registry.ASN1_ENCODING_SHORT_NAME)) + throw new IOException("Unknown or unsupported format: " + format); + } + + return engineGetEncoded(); + } + + protected String engineToString() + { + CPStringBuilder sb = new CPStringBuilder("p="); + if (p == null) + sb.append("???"); + else + sb.append("0x").append(p.toString(16)); + + sb.append(", g="); + if (g == null) + sb.append("???"); + else + sb.append("0x").append(g.toString(16)); + + sb.append(", q="); + if (q == null) + sb.append("???"); + else + sb.append("0x").append(q.toString(16)); + + sb.append(", l=").append(l); + + return sb.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/sig/DHParametersGenerator.java b/libjava/classpath/gnu/javax/crypto/jce/sig/DHParametersGenerator.java new file mode 100644 index 000000000..3687ac3ca --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/sig/DHParametersGenerator.java @@ -0,0 +1,152 @@ +/* DHParametersGenerator.java -- JCE Adapter for a generator of DH parameters + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.sig; + +import gnu.java.security.Registry; +import gnu.javax.crypto.jce.GnuCrypto; +import gnu.javax.crypto.key.dh.GnuDHKeyPairGenerator; +import gnu.javax.crypto.key.dh.RFC2631; + +import java.math.BigInteger; +import java.security.AlgorithmParameterGeneratorSpi; +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; + +import javax.crypto.spec.DHGenParameterSpec; +import javax.crypto.spec.DHParameterSpec; + +/** + * A JCE Adapter for a generator of DH parameters. + */ +public class DHParametersGenerator + extends AlgorithmParameterGeneratorSpi +{ + private static final Provider GNU_CRYPTO = new GnuCrypto(); + + /** Size of the prime (public) modulus in bits. */ + private int modulusSize = -1; + + /** Size of the prime (private) modulus in bits. */ + private int exponentSize = -1; + + /** User specified source of randomness. */ + private SecureRandom rnd; + + /** Our concrete DH parameters generator. */ + private RFC2631 rfc2631; + + + protected void engineInit(int size, SecureRandom random) + { + if ((size % 256) != 0 || size < GnuDHKeyPairGenerator.DEFAULT_PRIME_SIZE) + throw new InvalidParameterException("Prime modulus (p) size (in bits) " + + "MUST be a multiple of 256, and " + + "greater than or equal to 1024"); + this.modulusSize = size; + this.rnd = random; + } + + protected void engineInit(AlgorithmParameterSpec spec, SecureRandom random) + throws InvalidAlgorithmParameterException + { + if (spec instanceof DHParameterSpec) + { + DHParameterSpec dhSpec = (DHParameterSpec) spec; + BigInteger p = dhSpec.getP(); + int size = p.bitLength(); + this.engineInit(size, random); + } + else if (spec instanceof DHGenParameterSpec) + { + DHGenParameterSpec dhSpec = (DHGenParameterSpec) spec; + int size = dhSpec.getPrimeSize(); + this.engineInit(size, random); + exponentSize = dhSpec.getExponentSize(); + + if ((exponentSize % 8) != 0 + || exponentSize < GnuDHKeyPairGenerator.DEFAULT_EXPONENT_SIZE) + throw new InvalidParameterException("Random exponent size (in bits) " + + "MUST be a multiple of 8, and " + + "greater than or equal to " + + GnuDHKeyPairGenerator.DEFAULT_EXPONENT_SIZE); + if (exponentSize > modulusSize) + throw new InvalidParameterException("Random exponent size (in bits) " + + "MUST be less than that of the " + + "public prime modulus (p)"); + } + + throw new InvalidAlgorithmParameterException("Wrong AlgorithmParameterSpec type: " + + spec.getClass().getName()); + } + + protected AlgorithmParameters engineGenerateParameters() + { + if (modulusSize < 1) + modulusSize = GnuDHKeyPairGenerator.DEFAULT_PRIME_SIZE; + + if (exponentSize < 1) + exponentSize = GnuDHKeyPairGenerator.DEFAULT_EXPONENT_SIZE; + + rfc2631 = new RFC2631(exponentSize, modulusSize, rnd); + BigInteger[] params = rfc2631.generateParameters(); + BigInteger p = params[RFC2631.DH_PARAMS_P]; + BigInteger g = params[RFC2631.DH_PARAMS_G]; + int l = params[RFC2631.DH_PARAMS_Q].bitLength(); + DHParameterSpec spec = new DHParameterSpec(p, g, l); + AlgorithmParameters result = null; + try + { + result = AlgorithmParameters.getInstance(Registry.DH_KPG, GNU_CRYPTO); + result.init(spec); + } + catch (NoSuchAlgorithmException ignore) + { + } + catch (InvalidParameterSpecException ignore) + { + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/spec/BlockCipherParameterSpec.java b/libjava/classpath/gnu/javax/crypto/jce/spec/BlockCipherParameterSpec.java new file mode 100644 index 000000000..b17fa3497 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/spec/BlockCipherParameterSpec.java @@ -0,0 +1,122 @@ +/* BlockCipherParameterSpec.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.spec; + +import gnu.java.security.util.Util; + +import java.security.spec.AlgorithmParameterSpec; + +/** + * Block cipher parameters in GNU are the cipher's name, its block and key + * sizes, and an optional initialization vector. + */ +public class BlockCipherParameterSpec + implements AlgorithmParameterSpec +{ + /** The initialization vector. */ + protected byte[] iv; + /** The cipher's block size, in bytes. */ + protected int blockSize; + /** The cipher's key size, in bytes. */ + protected int keySize; + + /** + * Create a new parameter specification. + * + * @param iv The initialization vector, or null if there is no + * IV. + * @param blockSize The cipher's block size, in bytes. + * @param keySize The cipher's key size, in bytes. + */ + public BlockCipherParameterSpec(byte[] iv, int blockSize, int keySize) + { + this.iv = (iv != null) ? (byte[]) iv.clone() : null; + this.blockSize = blockSize; + this.keySize = keySize; + } + + /** + * Create a new parameter specification with no IV. + * + * @param blockSize The cipher's block size, in bytes. + * @param keySize The cipher's key size, in bytes. + */ + public BlockCipherParameterSpec(int blockSize, int keySize) + { + this(null, blockSize, keySize); + } + + /** + * Get the initialization vector for the cipher, or null if + * there is no IV. + * + * @return The IV. + */ + public byte[] getIV() + { + return iv; + } + + /** + * Get the block size of the cipher these parameters are for. + * + * @return The block size. + */ + public int getBlockSize() + { + return blockSize; + } + + /** + * Get the key size of the cipher these parameters are for. + * + * @return The block size. + */ + public int getKeySize() + { + return keySize; + } + + public String toString() + { + return getClass().getName() + " { " + + ((iv != null) ? ("IV=" + Util.toString(iv)) + ", " : "") + + "BS=" + blockSize + ", KS=" + keySize + " }"; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/spec/TMMHParameterSpec.java b/libjava/classpath/gnu/javax/crypto/jce/spec/TMMHParameterSpec.java new file mode 100644 index 000000000..31199538c --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/spec/TMMHParameterSpec.java @@ -0,0 +1,117 @@ +/* TMMHParameterSpec.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.spec; + +import gnu.java.security.prng.IRandom; + +import java.security.spec.AlgorithmParameterSpec; + +/** + * This class represents the algorithm parameters for the Truncated + * Multi-Modular Hash function for use with JCE-derived instances of + * {@link gnu.javax.crypto.mac.TMMH16}. + *

+ * This class is little more than a container for the key stream, tag length, + * and prefix parameters for the TMMH algorithm. + */ +public class TMMHParameterSpec + implements AlgorithmParameterSpec +{ + /** The keystream. */ + protected IRandom keystream; + /** The tag length. */ + protected Integer tagLength; + /** The prefix. */ + protected byte[] prefix; + + /** + * Create a new parameter specification. + * + * @param keystream The (PRNG) key stream. + * @param tagLength The tag length. + * @param prefix The prefix. + */ + public TMMHParameterSpec(IRandom keystream, Integer tagLength, byte[] prefix) + { + this.keystream = keystream; + this.tagLength = tagLength; + this.prefix = prefix; + } + + /** + * Create a new parameter specification with no prefix. + * + * @param keystream The (PRNG) key stream. + * @param tagLength The tag length. + */ + public TMMHParameterSpec(IRandom keystream, Integer tagLength) + { + this(keystream, tagLength, null); + } + + /** + * Return the key stream this specification was initialized with. + * + * @return The key stream. + */ + public IRandom getKeystream() + { + return keystream; + } + + /** + * Return the tag length this specification was initialized with. + * + * @return The tag length. + */ + public Integer getTagLength() + { + return tagLength; + } + + /** + * Return the prefix, or null if no prefix was specified. + * + * @return The prefix. + */ + public byte[] getPrefix() + { + return prefix; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/spec/UMac32ParameterSpec.java b/libjava/classpath/gnu/javax/crypto/jce/spec/UMac32ParameterSpec.java new file mode 100644 index 000000000..3c13faf04 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/spec/UMac32ParameterSpec.java @@ -0,0 +1,73 @@ +/* UMac32ParameterSpec.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.jce.spec; + +import java.security.spec.AlgorithmParameterSpec; + +/** + * This class represents the parameters for the UMAC-32 message authentication + * code algorithm. In practice this means the Nonce material used to + * initialize the algorithm. + */ +public class UMac32ParameterSpec + implements AlgorithmParameterSpec +{ + /** The Nonce material. */ + protected byte[] nonce; + + /** + * Create a new parameter instance. + * + * @param nonce The nonce material. + */ + public UMac32ParameterSpec(byte[] nonce) + { + this.nonce = nonce; + } + + /** + * Return the nonce material. + * + * @return The nonce material. + */ + public byte[] getNonce() + { + return nonce; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/BaseKeyAgreementParty.java b/libjava/classpath/gnu/javax/crypto/key/BaseKeyAgreementParty.java new file mode 100644 index 000000000..3f4e0a22c --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/BaseKeyAgreementParty.java @@ -0,0 +1,168 @@ +/* BaseKeyAgreementParty.java -- + Copyright (C) 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.crypto.key; + +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.PRNG; + +import java.math.BigInteger; +import java.security.SecureRandom; +import java.util.Map; + +/** + * A base abstract class to facilitate implementations of concrete key agreement + * protocol handlers. + */ +public abstract class BaseKeyAgreementParty + implements IKeyAgreementParty +{ + protected static final BigInteger TWO = BigInteger.valueOf(2L); + /** The canonical name of the protocol. */ + protected String name; + /** Whether the instance is initialised or not. */ + protected boolean initialised = false; + /** The current step index of the protocol exchange. */ + protected int step = -1; + /** Whether the exchange has concluded or not. */ + protected boolean complete = false; + /** The optional {@link SecureRandom} instance to use. */ + protected SecureRandom rnd = null; + /** The optional {@link IRandom} instance to use. */ + protected IRandom irnd = null; + /** Our default source of randomness. */ + private PRNG prng = null; + + protected BaseKeyAgreementParty(String name) + { + super(); + + this.name = name; + } + + public String name() + { + return name; + } + + public void init(Map attributes) throws KeyAgreementException + { + if (initialised) + throw new IllegalStateException("already initialised"); + this.engineInit(attributes); + initialised = true; + this.step = -1; + this.complete = false; + } + + public OutgoingMessage processMessage(IncomingMessage in) + throws KeyAgreementException + { + if (! initialised) + throw new IllegalStateException("not initialised"); + if (complete) + throw new IllegalStateException("exchange has already concluded"); + step++; + return this.engineProcessMessage(in); + } + + public boolean isComplete() + { + return complete; + } + + public byte[] getSharedSecret() throws KeyAgreementException + { + if (! initialised) + throw new KeyAgreementException("not yet initialised"); + if (! isComplete()) + throw new KeyAgreementException("not yet computed"); + return engineSharedSecret(); + } + + public void reset() + { + if (initialised) + { + this.engineReset(); + initialised = false; + } + } + + protected abstract void engineInit(Map attributes) + throws KeyAgreementException; + + protected abstract OutgoingMessage engineProcessMessage(IncomingMessage in) + throws KeyAgreementException; + + protected abstract byte[] engineSharedSecret() throws KeyAgreementException; + + protected abstract void engineReset(); + + /** + * Fills the designated byte array with random data. + * + * @param buffer the byte array to fill with random data. + */ + protected void nextRandomBytes(byte[] buffer) + { + if (rnd != null) + rnd.nextBytes(buffer); + else if (irnd != null) + try + { + irnd.nextBytes(buffer, 0, buffer.length); + } + catch (LimitReachedException lre) + { + irnd = null; + getDefaultPRNG().nextBytes(buffer); + } + else + getDefaultPRNG().nextBytes(buffer); + } + + private PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + + return prng; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/GnuPBEKey.java b/libjava/classpath/gnu/javax/crypto/key/GnuPBEKey.java new file mode 100644 index 000000000..5642e59ed --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/crypto/key/GnuSecretKey.java b/libjava/classpath/gnu/javax/crypto/key/GnuSecretKey.java new file mode 100644 index 000000000..c8ca1edab --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/GnuSecretKey.java @@ -0,0 +1,131 @@ +/* GnuSecretKey.java -- + Copyright (C) 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.crypto.key; + +import gnu.java.security.util.Util; +import java.security.Key; + +/** + * A secret key composed of a sequence of raw, unformatted octets. This class is + * analogous to the {@link javax.crypto.spec.SecretKeySpec} class, but is + * provided for platforms that do not or cannot contain that class. + */ +public class GnuSecretKey + implements Key +{ + private final byte[] key; + private final String algorithm; + + /** + * Creates a new secret key. The supplied byte array is copied by this + * constructor. + * + * @param key The raw, secret key. + * @param algorithm The algorithm name, which can be null or empty. + */ + public GnuSecretKey(byte[] key, String algorithm) + { + this(key, 0, key.length, algorithm); + } + + /** + * Creates a new secret key from a portion of a byte array. + * + * @param key The raw, secret key. + * @param offset The offset at which the key begins. + * @param length The number of bytes that comprise the key. + * @param algorithm The algorithm name, which can be null or empty. + */ + public GnuSecretKey(byte[] key, int offset, int length, String algorithm) + { + this.key = new byte[length]; + System.arraycopy(key, offset, this.key, 0, length); + this.algorithm = algorithm; + } + + /** + * Returns the algorithm name, if any. + * + * @return The algorithm name. + */ + public String getAlgorithm() + { + return null; + } + + /** + * Returns the encoded key, which is merely the byte array this class was + * created with. A reference to the internal byte array is returned, so the + * caller can delete this key from memory by modifying the returned array. + * + * @return The raw key. + */ + public byte[] getEncoded() + { + return key; + } + + /** + * Returns the string "RAW". + * + * @return The string "RAW". + */ + public String getFormat() + { + return "RAW"; + } + + public boolean equals(Object o) + { + if (! (o instanceof GnuSecretKey)) + return false; + if (key.length != ((GnuSecretKey) o).key.length) + return false; + byte[] key2 = ((GnuSecretKey) o).key; + for (int i = 0; i < key.length; i++) + if (key[i] != key2[i]) + return false; + return true; + } + + public String toString() + { + return "GnuSecretKey [ " + algorithm + " " + Util.toString(key) + " ]"; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/IKeyAgreementParty.java b/libjava/classpath/gnu/javax/crypto/key/IKeyAgreementParty.java new file mode 100644 index 000000000..64434212f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/IKeyAgreementParty.java @@ -0,0 +1,100 @@ +/* IKeyAgreementParty.java -- + Copyright (C) 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.crypto.key; + +import java.util.Map; + +/** + * The visible methods of an key agreement protocol participating party. + */ +public interface IKeyAgreementParty +{ + /** + * Returns the canonical name of the key agreement protocol. + * + * @return the canonical name of the key agreement protocol. + */ + String name(); + + /** + * Sets up the instance to operate with specific attributes. + * + * @param attributes a map of name-values used by concrete implementations. + * @throws KeyAgreementException if an exception occurs during the setup. + */ + void init(Map attributes) throws KeyAgreementException; + + /** + * Processes an incoming message at one end, generating a message that will be + * processed by the other party(ies). + * + * @param in the incoming message. + * @return an outgoing message, or null if this is an + * intermediary step that does not cause any output. + * @throws KeyAgreementException if an exception occurs during the processing + * of the incoming message, or during the generation of the outgoing + * message. + */ + OutgoingMessage processMessage(IncomingMessage in) + throws KeyAgreementException; + + /** + * Returns true if the party in the key agreement protocol + * exchange has completed its part of the exchange. If this is the case an + * {@link IllegalStateException} is thrown for any method invocation except + * init() or reset(). + * + * @return true if this party has completed its part of the key + * agreement protocol exchange; false otherwise. + */ + boolean isComplete(); + + /** + * Returns the byte array containing the shared secret as generated by this + * party. + * + * @return the generated shared secret. + * @throws KeyAgreementException if the key agreement is not yet initialised, + * or is initialised but the exchange is still in progress. + */ + byte[] getSharedSecret() throws KeyAgreementException; + + /** Resets this instance for re-use with another set of attributes. */ + void reset(); +} diff --git a/libjava/classpath/gnu/javax/crypto/key/IncomingMessage.java b/libjava/classpath/gnu/javax/crypto/key/IncomingMessage.java new file mode 100644 index 000000000..3b68392d6 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/IncomingMessage.java @@ -0,0 +1,318 @@ +/* IncomingMessage.java -- + Copyright (C) 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.crypto.key; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; +import gnu.java.security.key.dss.DSSKeyPairPKCS8Codec; +import gnu.java.security.key.dss.DSSKeyPairRawCodec; +import gnu.java.security.key.dss.DSSKeyPairX509Codec; +import gnu.java.security.key.rsa.RSAKeyPairPKCS8Codec; +import gnu.java.security.key.rsa.RSAKeyPairRawCodec; +import gnu.java.security.key.rsa.RSAKeyPairX509Codec; +import gnu.javax.crypto.key.dh.DHKeyPairPKCS8Codec; +import gnu.javax.crypto.key.dh.DHKeyPairRawCodec; +import gnu.javax.crypto.key.dh.DHKeyPairX509Codec; +import gnu.javax.crypto.key.srp6.SRPKeyPairRawCodec; + +import java.io.ByteArrayInputStream; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; + +/** + * An implementation of an incoming message for use with key agreement + * protocols. + */ +public class IncomingMessage +{ + /** The internal buffer stream containing the message's contents. */ + protected ByteArrayInputStream in; + /** The length of the message contents, according to its 4-byte header. */ + protected int length; + + /** + * Constructs an incoming message given the message's encoded form, including + * its header bytes. + * + * @param b the encoded form, including the header bytes, of an incoming + * message. + * @throws KeyAgreementException if the buffer is malformed. + */ + public IncomingMessage(byte[] b) throws KeyAgreementException + { + this(); + + if (b.length < 4) + throw new KeyAgreementException("message header too short"); + length = b[0] << 24 + | (b[1] & 0xFF) << 16 + | (b[2] & 0xFF) << 8 + | (b[3] & 0xFF); + if (length > Registry.SASL_BUFFER_MAX_LIMIT || length < 0) + throw new KeyAgreementException("message size limit exceeded"); + in = new ByteArrayInputStream(b, 4, length); + } + + /** Trivial private constructor for use by the class method. */ + private IncomingMessage() + { + super(); + } + + /** + * Returns an instance of a message given its encoded contents, excluding the + * message's header bytes. + *

+ * Calls the method with the same name and three arguments as: + * getInstance(raw, 0, raw.length). + * + * @param raw the encoded form, excluding the header bytes. + * @return a new instance of IncomingMessage. + */ + public static IncomingMessage getInstance(byte[] raw) + { + return getInstance(raw, 0, raw.length); + } + + /** + * Returns an instance of a message given its encoded contents, excluding the + * message's header bytes. + * + * @param raw the encoded form, excluding the header bytes. + * @param offset offset where to start using raw bytes from. + * @param len number of bytes to use. + * @return a new instance of IncomingMessage. + */ + public static IncomingMessage getInstance(byte[] raw, int offset, int len) + { + IncomingMessage result = new IncomingMessage(); + result.in = new ByteArrayInputStream(raw, offset, len); + return result; + } + + /** + * Converts two octets into the number that they represent. + * + * @param b the two octets. + * @return the length. + */ + public static int twoBytesToLength(byte[] b) throws KeyAgreementException + { + int result = (b[0] & 0xFF) << 8 | (b[1] & 0xFF); + if (result > Registry.SASL_TWO_BYTE_MAX_LIMIT) + throw new KeyAgreementException("encoded MPI size limit exceeded"); + return result; + } + + /** + * Converts four octets into the number that they represent. + * + * @param b the four octets. + * @return the length. + */ + public static int fourBytesToLength(byte[] b) throws KeyAgreementException + { + int result = b[0] << 24 + | (b[1] & 0xFF) << 16 + | (b[2] & 0xFF) << 8 + | (b[3] & 0xFF); + if (result > Registry.SASL_FOUR_BYTE_MAX_LIMIT || result < 0) + throw new KeyAgreementException("encoded entity size limit exceeded"); + return result; + } + + public boolean hasMoreElements() + { + return (in.available() > 0); + } + + /** + * Decodes a public key from the message. + *

+ * See {@link OutgoingMessage#writePublicKey(java.security.PublicKey)} for + * more details on the internal format. + * + * @throws KeyAgreementException if an encoding size constraint is violated or + * a mismatch was detected in the encoding. + */ + public PublicKey readPublicKey() throws KeyAgreementException + { + if (in.available() < 5) + throw new KeyAgreementException("not enough bytes for a public key in message"); + byte[] elementLengthBytes = new byte[4]; + in.read(elementLengthBytes, 0, 4); + int elementLength = fourBytesToLength(elementLengthBytes); + if (in.available() < elementLength) + throw new KeyAgreementException("illegal public key encoding"); + int keyTypeAndFormatID = in.read() & 0xFF; + elementLength--; + byte[] kb = new byte[elementLength]; + in.read(kb, 0, elementLength); + // instantiate the right codec and decode + IKeyPairCodec kpc = getKeyPairCodec(keyTypeAndFormatID); + return kpc.decodePublicKey(kb); + } + + /** + * Decodes a private key from the message. + *

+ * See {@link OutgoingMessage#writePrivateKey(java.security.PrivateKey)} for + * more details. + * + * @throws KeyAgreementException if an encoding size constraint is violated or + * a mismatch was detected in the encoding. + */ + public PrivateKey readPrivateKey() throws KeyAgreementException + { + if (in.available() < 5) + throw new KeyAgreementException("not enough bytes for a private key in message"); + byte[] elementLengthBytes = new byte[4]; + in.read(elementLengthBytes, 0, 4); + int elementLength = fourBytesToLength(elementLengthBytes); + if (in.available() < elementLength) + throw new KeyAgreementException("illegal private key encoding"); + int keyTypeAndFormatID = in.read() & 0xFF; + elementLength--; + byte[] kb = new byte[elementLength]; + in.read(kb, 0, elementLength); + // instantiate the right codec and decode + IKeyPairCodec kpc = getKeyPairCodec(keyTypeAndFormatID); + return kpc.decodePrivateKey(kb); + } + + /** + * Decodes an MPI from the current message's contents. + * + * @return a native representation of an MPI. + * @throws KeyAgreementException if an encoding exception occurs during the + * operation. + */ + public BigInteger readMPI() throws KeyAgreementException + { + if (in.available() < 2) + throw new KeyAgreementException("not enough bytes for an MPI in message"); + byte[] elementLengthBytes = new byte[2]; + in.read(elementLengthBytes, 0, 2); + int elementLength = twoBytesToLength(elementLengthBytes); + if (in.available() < elementLength) + throw new KeyAgreementException("illegal MPI encoding"); + byte[] element = new byte[elementLength]; + in.read(element, 0, element.length); + return new BigInteger(1, element); + } + + public String readString() throws KeyAgreementException + { + if (in.available() < 2) + throw new KeyAgreementException("not enough bytes for a text in message"); + byte[] elementLengthBytes = new byte[2]; + in.read(elementLengthBytes, 0, 2); + int elementLength = twoBytesToLength(elementLengthBytes); + if (in.available() < elementLength) + throw new KeyAgreementException("illegal text encoding"); + byte[] element = new byte[elementLength]; + in.read(element, 0, element.length); + String result = null; + try + { + result = new String(element, "UTF8"); + } + catch (UnsupportedEncodingException x) + { + throw new KeyAgreementException("unxupported UTF8 encoding", x); + } + return result; + } + + private IKeyPairCodec getKeyPairCodec(int keyTypeAndFormatID) + throws KeyAgreementException + { + int keyType = (keyTypeAndFormatID >>> 4) & 0x0F; + int formatID = keyTypeAndFormatID & 0x0F; + switch (formatID) + { + case Registry.RAW_ENCODING_ID: + switch (keyType) + { + case 0: + return new DSSKeyPairRawCodec(); + case 1: + return new RSAKeyPairRawCodec(); + case 2: + return new DHKeyPairRawCodec(); + case 3: + return new SRPKeyPairRawCodec(); + default: + throw new KeyAgreementException("Unknown key-type for Raw format: " + + keyType); + } + case Registry.X509_ENCODING_ID: + switch (keyType) + { + case 0: + return new DSSKeyPairX509Codec(); + case 1: + return new RSAKeyPairX509Codec(); + case 2: + return new DHKeyPairX509Codec(); + default: + throw new KeyAgreementException("Unknown key-type for X.509 format: " + + keyType); + } + case Registry.PKCS8_ENCODING_ID: + switch (keyType) + { + case 0: + return new DSSKeyPairPKCS8Codec(); + case 1: + return new RSAKeyPairPKCS8Codec(); + case 2: + return new DHKeyPairPKCS8Codec(); + default: + throw new KeyAgreementException("Unknown key-type for PKCS#8 format: " + + keyType); + } + default: + throw new KeyAgreementException("Unknown format identifier: " + + formatID); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/KeyAgreementException.java b/libjava/classpath/gnu/javax/crypto/key/KeyAgreementException.java new file mode 100644 index 000000000..06a7db70b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/KeyAgreementException.java @@ -0,0 +1,168 @@ +/* KeyAgreementException.java -- + Copyright (C) 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.crypto.key; + +import gnu.java.lang.CPStringBuilder; + +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.Serializable; +import java.security.KeyManagementException; + +/** + * A generic exception indicating that an unexpected condition has been detected + * during the setup and/or processing of a key agreement protocol exchange. + */ +public class KeyAgreementException + extends KeyManagementException + implements Serializable +{ + /** @serial The possibly null root cause exception. */ + private Throwable cause = null; + + /** + * Constructs a new instance of KeyAgreementException. The + * root exception and the detailed message are null. + */ + public KeyAgreementException() + { + super(); + } + + /** + * Constructs a new instance of KeyAgreementException with a + * detailed message. The root exception is null. + * + * @param detail a possibly null string containing details of + * the exception. + * @see Throwable#getMessage() + */ + public KeyAgreementException(String detail) + { + super(detail); + } + + /** + * Constructs a new instance of KeyAgreementException with a + * detailed message and a root exception. + * + * @param detail a possibly null string containing details of + * the exception. + * @param cause a possibly null root exception that caused this + * exception. + * @see Throwable#getMessage() + * @see #getCause() + */ + public KeyAgreementException(String detail, Throwable cause) + { + super(detail); + this.cause = cause; + } + + /** + * Returns the cause of this throwable or null if the cause is + * nonexistent or unknown. The cause is the throwable that caused this + * exception to be thrown. + * + * @return the possibly null exception that caused this one. + */ + public Throwable getCause() + { + return cause; + } + + /** + * Prints this exception's stack trace to System.err. If this + * exception has a root exception; the stack trace of the root + * exception is also printed to System.err. + */ + public void printStackTrace() + { + super.printStackTrace(); + if (cause != null) + cause.printStackTrace(); + } + + /** + * Prints this exception's stack trace to a print stream. If this exception + * has a root exception; the stack trace of the root exception + * is also printed to the print stream. + * + * @param ps the non-null print stream to which to print. + */ + public void printStackTrace(PrintStream ps) + { + super.printStackTrace(ps); + if (cause != null) + cause.printStackTrace(ps); + } + + /** + * Prints this exception's stack trace to a print writer. If this exception + * has a root exception; the stack trace of the root exception + * is also printed to the print writer. + * + * @param pw the non-null print writer to use for output. + */ + public void printStackTrace(PrintWriter pw) + { + super.printStackTrace(pw); + if (cause != null) + cause.printStackTrace(pw); + } + + /** + * Returns the string representation of this exception. The string + * representation contains this exception's class name, its detailed messsage, + * and if it has a root exception, the string representation of the + * root exception. This string representation is meant for debugging and is + * not meant to be interpreted programmatically. + * + * @return the non-null string representation of this exception. + * @see Throwable#getMessage() + */ + public String toString() + { + CPStringBuilder sb = new CPStringBuilder(this.getClass().getName()).append(": ") + .append(super.toString()); + if (cause != null) + sb.append("; caused by: ").append(cause.toString()); + return sb.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/KeyAgreementFactory.java b/libjava/classpath/gnu/javax/crypto/key/KeyAgreementFactory.java new file mode 100644 index 000000000..a4e14bc69 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/KeyAgreementFactory.java @@ -0,0 +1,143 @@ +/* KeyAgreementFactory.java -- + Copyright (C) 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.crypto.key; + +import gnu.java.security.Registry; + +import gnu.javax.crypto.key.dh.DiffieHellmanSender; +import gnu.javax.crypto.key.dh.DiffieHellmanReceiver; +import gnu.javax.crypto.key.dh.ElGamalSender; +import gnu.javax.crypto.key.dh.ElGamalReceiver; +import gnu.javax.crypto.key.srp6.SRP6Host; +import gnu.javax.crypto.key.srp6.SRP6User; +import gnu.javax.crypto.key.srp6.SRP6SaslClient; +import gnu.javax.crypto.key.srp6.SRP6SaslServer; +import gnu.javax.crypto.key.srp6.SRP6TLSClient; +import gnu.javax.crypto.key.srp6.SRP6TLSServer; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * A Factory class to generate key agreement protocol handlers. + */ +public class KeyAgreementFactory +{ + /** Trivial constructor to enforce Singleton pattern. */ + private KeyAgreementFactory() + { + super(); + } + + /** + * Returns an instance of a key agreeent protocol handler, for party + * A in a two-party A..B exchange, given the + * canonical name of this protocol. Party A is usually the + * initiator of the exchange. + * + * @param name the case-insensitive key agreement protocol name. + * @return an instance of the key agreement protocol handler for party + * A, or null if none found. + */ + public static IKeyAgreementParty getPartyAInstance(String name) + { + if (name == null) + return null; + name = name.trim(); + IKeyAgreementParty result = null; + if (name.equalsIgnoreCase(Registry.DH_KA)) + result = new DiffieHellmanSender(); + else if (name.equalsIgnoreCase(Registry.ELGAMAL_KA)) + result = new ElGamalSender(); + else if (name.equalsIgnoreCase(Registry.SRP6_KA)) + result = new SRP6User(); + else if (name.equalsIgnoreCase(Registry.SRP_SASL_KA)) + result = new SRP6SaslClient(); + else if (name.equalsIgnoreCase(Registry.SRP_TLS_KA)) + result = new SRP6TLSClient(); + return result; + } + + /** + * Returns an instance of a key agreeent protocol handler, for party + * B in a two-party A..B exchange, given the + * canonical name of this protocol. + * + * @param name the case-insensitive key agreement protocol name. + * @return an instance of the key agreement protocol handler for party + * B, or null if none found. + */ + public static IKeyAgreementParty getPartyBInstance(String name) + { + if (name == null) + return null; + name = name.trim(); + IKeyAgreementParty result = null; + if (name.equalsIgnoreCase(Registry.DH_KA)) + result = new DiffieHellmanReceiver(); + else if (name.equalsIgnoreCase(Registry.ELGAMAL_KA)) + result = new ElGamalReceiver(); + else if (name.equalsIgnoreCase(Registry.SRP6_KA)) + result = new SRP6Host(); + else if (name.equalsIgnoreCase(Registry.SRP_SASL_KA)) + result = new SRP6SaslServer(); + else if (name.equalsIgnoreCase(Registry.SRP_TLS_KA)) + result = new SRP6TLSServer(); + return result; + } + + /** + * Returns a {@link Set} of key agreement protocol names supported by this + * Factory. + * + * @return a {@link Set} of key agreement protocol names (Strings). + */ + public static final Set getNames() + { + HashSet hs = new HashSet(); + hs.add(Registry.DH_KA); + hs.add(Registry.ELGAMAL_KA); + hs.add(Registry.SRP6_KA); + hs.add(Registry.SRP_SASL_KA); + hs.add(Registry.SRP_TLS_KA); + + return Collections.unmodifiableSet(hs); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/OutgoingMessage.java b/libjava/classpath/gnu/javax/crypto/key/OutgoingMessage.java new file mode 100644 index 000000000..e011330fe --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/OutgoingMessage.java @@ -0,0 +1,234 @@ +/* OutgoingMessage.java -- + Copyright (C) 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.crypto.key; + +import gnu.java.security.Registry; +import gnu.java.security.key.dss.DSSKey; +import gnu.java.security.key.rsa.GnuRSAKey; +import gnu.java.security.util.FormatUtil; +import gnu.javax.crypto.key.dh.GnuDHKey; +import gnu.javax.crypto.key.srp6.SRPKey; + +import java.io.ByteArrayOutputStream; +import java.io.UnsupportedEncodingException; +import java.security.Key; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.math.BigInteger; + +/** + * An implementation of outgoing messages for use with key agreement protocols. + */ +public class OutgoingMessage +{ + /** The internal output stream. */ + private ByteArrayOutputStream out; + + public OutgoingMessage() + { + super(); + + out = new ByteArrayOutputStream(); + } + + /** + * Returns the encoded form of the current message including the 4-byte length + * header. + * + * @throws KeyAgreementException if an encoding size constraint is violated. + */ + public byte[] toByteArray() throws KeyAgreementException + { + byte[] buffer = wrap(); + int length = buffer.length; + byte[] result = new byte[length + 4]; + result[0] = (byte)(length >>> 24); + result[1] = (byte)(length >>> 16); + result[2] = (byte)(length >>> 8); + result[3] = (byte) length; + System.arraycopy(buffer, 0, result, 4, length); + return result; + } + + /** + * Returns the encoded form of the current message excluding the 4-byte length + * header. + * + * @throws KeyAgreementException if an encoding size constraint is violated. + */ + public byte[] wrap() throws KeyAgreementException + { + int length = out.size(); + if (length > Registry.SASL_BUFFER_MAX_LIMIT || length < 0) + throw new KeyAgreementException("message content is too long"); + return out.toByteArray(); + } + + /** + * Encodes a public key into the message. + *

+ * When a public key is encoded into an outgoing message, the byte array of + * the encoded key --according to its encoding/decoding format specified when + * the key was first instantiated-- are put in the message (a) preceeded by + * one byte representing both the type of key (upper 4-bit) and the identifier + * of the format used (lower 4-bit), and (b) preceeed by a 4-byte entity + * representing the total length, excluding these 4 bytes, of the bytes + * representing the encoded key and the one-byte representing the key-type and + * format; i.e. + *

+   * key --> 4-byte-length || 1-byte-type-and-format || encoded-key-bytes
+   * 
+ * + * @param k the public key to encode. + * @throws KeyAgreementException if an encoding size constraint is violated. + */ + public void writePublicKey(PublicKey k) throws KeyAgreementException + { + writeKey(k); + } + + /** + * Encodes a private key into the message. + *

+ * When a private key is encoded into an outgoing message, the byte array of + * the encoded key --according to its encoding/decoding format specified when + * the key was first instantiated-- are put in the message (a) preceeded by + * one byte representing both the type of key (upper 4-bit) and the identifier + * of the format used (lower 4-bit), and (b) preceeed by a 4-byte entity + * representing the total length, excluding these 4 bytes, of the bytes + * representing the encoded key and the one-byte representing the key-type and + * format; i.e. + *

+   * key --> 4-byte-length || 1-byte-type-and-format || encoded-key-bytes
+   * 
+ * + * @param k the private key to encode. + * @throws KeyAgreementException if an encoding size constraint is violated. + */ + public void writePrivateKey(PrivateKey k) throws KeyAgreementException + { + writeKey(k); + } + + /** + * Encodes an MPI into the message. + * + * @param val the MPI to encode. + * @throws KeyAgreementException if an encoding size constraint is violated. + */ + public void writeMPI(BigInteger val) throws KeyAgreementException + { + byte[] b = val.toByteArray(); + int length = b.length; + if (length > Registry.SASL_TWO_BYTE_MAX_LIMIT) + throw new KeyAgreementException("MPI is too long"); + byte[] lengthBytes = { (byte)(length >>> 8), (byte) length }; + out.write(lengthBytes, 0, 2); + out.write(b, 0, b.length); + } + + /** + * Encodes a string into the message. + * + * @param s the string to encode. + * @throws KeyAgreementException if the UTF8 encoding is not supported on this + * platform, or if an encoding size constraint is violated. + */ + public void writeString(String s) throws KeyAgreementException + { + byte[] b = null; + try + { + b = s.getBytes("UTF8"); + } + catch (UnsupportedEncodingException x) + { + throw new KeyAgreementException("unxupported UTF8 encoding", x); + } + int length = b.length; + if (length > Registry.SASL_TWO_BYTE_MAX_LIMIT) + throw new KeyAgreementException("text too long"); + byte[] lengthBytes = { (byte)(length >>> 8), (byte) length }; + out.write(lengthBytes, 0, 2); + out.write(b, 0, b.length); + } + + /** + * @param k the key to encode. + * @throws KeyAgreementException if an encoding size constraint is violated. + */ + private void writeKey(Key k) throws KeyAgreementException + { + byte[] b = k.getEncoded(); + int keyType = getKeyType(k); + int formatID = FormatUtil.getFormatID(k.getFormat()); + int length = b.length + 1; + if (length > Registry.SASL_FOUR_BYTE_MAX_LIMIT) + throw new KeyAgreementException("Encoded key is too long"); + byte[] lengthBytes = { + (byte)(length >>> 24), + (byte)(length >>> 16), + (byte)(length >>> 8), + (byte) length }; + out.write(lengthBytes, 0, 4); + out.write(((keyType & 0x0F) << 4) | (formatID & 0x0F)); + out.write(b, 0, b.length); + } + + /** + * @param k the key to find an identifier for. + * @return an integer from 0 to 3 identifying + * the type of key. + * @throws KeyAgreementException if the designated key is of unknown or + * unsupported type. + */ + private int getKeyType(Key k) throws KeyAgreementException + { + if (k instanceof DSSKey) + return 0; + if (k instanceof GnuRSAKey) + return 1; + if (k instanceof GnuDHKey) + return 2; + if (k instanceof SRPKey) + return 3; + throw new KeyAgreementException("Unknown or unsupported key type: " + + k.getClass().getName()); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairPKCS8Codec.java b/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairPKCS8Codec.java new file mode 100644 index 000000000..8c03cbb00 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairPKCS8Codec.java @@ -0,0 +1,240 @@ +/* DHKeyPairPKCS8Codec.java -- PKCS#8 encoder/decoder for DH keys + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.dh; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidParameterException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.ArrayList; + +import gnu.java.security.OID; +import gnu.java.security.Registry; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.der.DERWriter; +import gnu.java.security.key.IKeyPairCodec; +import gnu.java.security.util.DerUtil; +import gnu.java.security.util.Util; + +public class DHKeyPairPKCS8Codec + implements IKeyPairCodec +{ + private static final OID DH_ALG_OID = new OID(Registry.DH_OID_STRING); + + // implicit 0-arguments constructor + + public int getFormatID() + { + return PKCS8_FORMAT; + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public byte[] encodePublicKey(PublicKey key) + { + throw new InvalidParameterException("Wrong format for public keys"); + } + + /** + * Returns the DER-encoded form of the PKCS#8 ASN.1 PrivateKeyInfo + * representation of a DH private key. The ASN.1 specification is as follows: + * + *
+   *   PrivateKeyInfo ::= SEQUENCE {
+   *     version              INTEGER, -- MUST be 0
+   *     privateKeyAlgorithm  AlgorithmIdentifier,
+   *     privateKey           OCTET STRING
+   *   }
+   *
+   *   AlgorithmIdentifier ::= SEQUENCE {
+   *     algorithm   OBJECT IDENTIFIER,
+   *     parameters  ANY DEFINED BY algorithm OPTIONAL
+   *   }
+   *
+   *   DhParams ::= SEQUENCE {
+   *     p  INTEGER, -- odd prime, p=jq +1
+   *     g  INTEGER, -- generator, g
+   *     q  INTEGER  -- factor of p-1
+   *   }
+   * 
+ *

+ * IMPORTANT: with RI's {@link javax.crypto.spec.DHGenParameterSpec} + * and {@link javax.crypto.spec.DHParameterSpec} classes, we may end up with + * Diffie-Hellman keys that have a null for the q + * parameter. RFC-2631 DOES NOT allow for an optional value for that + * parameter, hence we replace such null values with 0, and do + * the reverse in the corresponding decode method. + * + * @return the DER encoded form of the ASN.1 representation of the + * PrivateKeyInfo field in an X.509 certificate. + * @throw InvalidParameterException if an error occurs during the marshalling + * process. + */ + public byte[] encodePrivateKey(PrivateKey key) + { + if (! (key instanceof GnuDHPrivateKey)) + throw new InvalidParameterException("Wrong key type"); + + DERValue derVersion = new DERValue(DER.INTEGER, BigInteger.ZERO); + + DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DH_ALG_OID); + + GnuDHPrivateKey pk = (GnuDHPrivateKey) key; + BigInteger p = pk.getParams().getP(); + BigInteger g = pk.getParams().getG(); + BigInteger q = pk.getQ(); + if (q == null) + q = BigInteger.ZERO; + BigInteger x = pk.getX(); + + ArrayList params = new ArrayList(3); + params.add(new DERValue(DER.INTEGER, p)); + params.add(new DERValue(DER.INTEGER, g)); + params.add(new DERValue(DER.INTEGER, q)); + DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params); + + ArrayList algorithmID = new ArrayList(2); + algorithmID.add(derOID); + algorithmID.add(derParams); + DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + algorithmID); + + DERValue derPrivateKey = new DERValue(DER.OCTET_STRING, Util.trim(x)); + + ArrayList pki = new ArrayList(3); + pki.add(derVersion); + pki.add(derAlgorithmID); + pki.add(derPrivateKey); + DERValue derPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, pki); + + byte[] result; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try + { + DERWriter.write(baos, derPKI); + result = baos.toByteArray(); + } + catch (IOException e) + { + InvalidParameterException y = new InvalidParameterException(); + y.initCause(e); + throw y; + } + + return result; + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public PublicKey decodePublicKey(byte[] input) + { + throw new InvalidParameterException("Wrong format for public keys"); + } + + /** + * @param input the byte array to unmarshall into a valid DH + * {@link PrivateKey} instance. MUST NOT be null. + * @return a new instance of a {@link GnuDHPrivateKey} decoded from the + * PrivateKeyInfo material fed as input. + * @throw InvalidParameterException if an exception occurs during the + * unmarshalling process. + */ + public PrivateKey decodePrivateKey(byte[] input) + { + if (input == null) + throw new InvalidParameterException("Input bytes MUST NOT be null"); + + BigInteger version, p, q, g, x; + DERReader der = new DERReader(input); + try + { + DERValue derPKI = der.read(); + DerUtil.checkIsConstructed(derPKI, "Wrong PrivateKeyInfo field"); + + DERValue derVersion = der.read(); + if (! (derVersion.getValue() instanceof BigInteger)) + throw new InvalidParameterException("Wrong Version field"); + + version = (BigInteger) derVersion.getValue(); + if (version.compareTo(BigInteger.ZERO) != 0) + throw new InvalidParameterException("Unexpected Version: " + version); + + DERValue derAlgoritmID = der.read(); + DerUtil.checkIsConstructed(derAlgoritmID, "Wrong AlgorithmIdentifier field"); + + DERValue derOID = der.read(); + OID algOID = (OID) derOID.getValue(); + if (! algOID.equals(DH_ALG_OID)) + throw new InvalidParameterException("Unexpected OID: " + algOID); + + DERValue derParams = der.read(); + DerUtil.checkIsConstructed(derParams, "Wrong DSS Parameters field"); + + DERValue val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong P field"); + p = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong G field"); + g = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong Q field"); + q = (BigInteger) val.getValue(); + if (q.compareTo(BigInteger.ZERO) == 0) + q = null; + + val = der.read(); + byte[] xBytes = (byte[]) val.getValue(); + x = new BigInteger(1, xBytes); + } + catch (IOException e) + { + InvalidParameterException y = new InvalidParameterException(); + y.initCause(e); + throw y; + } + + return new GnuDHPrivateKey(Registry.PKCS8_ENCODING_ID, q, p, g, x); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java b/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java new file mode 100644 index 000000000..4275389ce --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java @@ -0,0 +1,336 @@ +/* DHKeyPairRawCodec.java -- + Copyright (C) 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.crypto.key.dh; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.io.ByteArrayOutputStream; +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; + +/** + * An object that implements the {@link IKeyPairCodec} operations for the + * Raw format to use with Diffie-Hellman keypairs. + */ +public class DHKeyPairRawCodec + implements IKeyPairCodec +{ + public int getFormatID() + { + return RAW_FORMAT; + } + + /** + * Returns the encoded form of the designated Diffie-Hellman public key + * according to the Raw format supported by this library. + *

+ * The Raw format for a DH public key, in this implementation, is a + * byte sequence consisting of the following: + *

    + *
  1. 4-byte magic consisting of the value of the literal + * {@link Registry#MAGIC_RAW_DH_PUBLIC_KEY},
  2. + *
  3. 1-byte version consisting of the constant: 0x01,
  4. + *
  5. 4-byte count of following bytes representing the DH parameter + * q in internet order,
  6. + *
  7. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DH parameter q, + *
  8. + *
  9. 4-byte count of following bytes representing the DH parameter + * p in internet order,
  10. + *
  11. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DH parameter p, + *
  12. + *
  13. 4-byte count of following bytes representing the DH parameter + * g,
  14. + *
  15. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DH parameter g, + *
  16. + *
  17. 4-byte count of following bytes representing the DH parameter + * y,
  18. + *
  19. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DH parameter y, + *
  20. + *
+ * + * @param key the key to encode. + * @return the Raw format encoding of the designated key. + * @throws IllegalArgumentException if the designated key is not a DH one. + * @see Registry#MAGIC_RAW_DH_PUBLIC_KEY + */ + public byte[] encodePublicKey(PublicKey key) + { + if (! (key instanceof GnuDHPublicKey)) + throw new IllegalArgumentException("key"); + GnuDHPublicKey dhKey = (GnuDHPublicKey) key; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + // magic + baos.write(Registry.MAGIC_RAW_DH_PUBLIC_KEY[0]); + baos.write(Registry.MAGIC_RAW_DH_PUBLIC_KEY[1]); + baos.write(Registry.MAGIC_RAW_DH_PUBLIC_KEY[2]); + baos.write(Registry.MAGIC_RAW_DH_PUBLIC_KEY[3]); + // version + baos.write(0x01); + // q + byte[] buffer = dhKey.getQ().toByteArray(); + int length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + // p + buffer = dhKey.getParams().getP().toByteArray(); + length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + // g + buffer = dhKey.getParams().getG().toByteArray(); + length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + // y + buffer = dhKey.getY().toByteArray(); + length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + return baos.toByteArray(); + } + + public PublicKey decodePublicKey(byte[] k) + { + // magic + if (k[0] != Registry.MAGIC_RAW_DH_PUBLIC_KEY[0] + || k[1] != Registry.MAGIC_RAW_DH_PUBLIC_KEY[1] + || k[2] != Registry.MAGIC_RAW_DH_PUBLIC_KEY[2] + || k[3] != Registry.MAGIC_RAW_DH_PUBLIC_KEY[3]) + throw new IllegalArgumentException("magic"); + // version + if (k[4] != 0x01) + throw new IllegalArgumentException("version"); + int i = 5; + int l; + byte[] buffer; + // q + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger q = new BigInteger(1, buffer); + // p + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger p = new BigInteger(1, buffer); + // g + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger g = new BigInteger(1, buffer); + // y + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger y = new BigInteger(1, buffer); + return new GnuDHPublicKey(q, p, g, y); + } + + /** + * Returns the encoded form of the designated Diffie-Hellman private key + * according to the Raw format supported by this library. + *

+ * The Raw format for a DH private key, in this implementation, is a + * byte sequence consisting of the following: + *

    + *
  1. 4-byte magic consisting of the value of the literal + * {@link Registry#MAGIC_RAW_DH_PRIVATE_KEY},
  2. + *
  3. 1-byte version consisting of the constant: 0x01,
  4. + *
  5. 4-byte count of following bytes representing the DH parameter + * q,
  6. + *
  7. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DH parameter q, + *
  8. + *
  9. 4-byte count of following bytes representing the DH parameter + * p in internet order,
  10. + *
  11. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DH parameter p, + *
  12. + *
  13. 4-byte count of following bytes representing the DH parameter + * g,
  14. + *
  15. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DH parameter g, + *
  16. + *
  17. 4-byte count of following bytes representing the DH parameter + * x,
  18. + *
  19. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DH parameter x, + *
  20. + *
+ * + * @param key the key to encode. + * @return the Raw format encoding of the designated key. + * @throws IllegalArgumentException if the designated key is not a DH one. + * @see Registry#MAGIC_RAW_DH_PRIVATE_KEY + */ + public byte[] encodePrivateKey(PrivateKey key) + { + if (! (key instanceof GnuDHPrivateKey)) + throw new IllegalArgumentException("key"); + GnuDHPrivateKey dhKey = (GnuDHPrivateKey) key; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + // magic + baos.write(Registry.MAGIC_RAW_DH_PRIVATE_KEY[0]); + baos.write(Registry.MAGIC_RAW_DH_PRIVATE_KEY[1]); + baos.write(Registry.MAGIC_RAW_DH_PRIVATE_KEY[2]); + baos.write(Registry.MAGIC_RAW_DH_PRIVATE_KEY[3]); + // version + baos.write(0x01); + // q + byte[] buffer = dhKey.getQ().toByteArray(); + int length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + // p + buffer = dhKey.getParams().getP().toByteArray(); + length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + // g + buffer = dhKey.getParams().getG().toByteArray(); + length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + // x + buffer = dhKey.getX().toByteArray(); + length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + return baos.toByteArray(); + } + + public PrivateKey decodePrivateKey(byte[] k) + { + // magic + if (k[0] != Registry.MAGIC_RAW_DH_PRIVATE_KEY[0] + || k[1] != Registry.MAGIC_RAW_DH_PRIVATE_KEY[1] + || k[2] != Registry.MAGIC_RAW_DH_PRIVATE_KEY[2] + || k[3] != Registry.MAGIC_RAW_DH_PRIVATE_KEY[3]) + throw new IllegalArgumentException("magic"); + // version + if (k[4] != 0x01) + throw new IllegalArgumentException("version"); + int i = 5; + int l; + byte[] buffer; + // q + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger q = new BigInteger(1, buffer); + // p + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger p = new BigInteger(1, buffer); + // g + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger g = new BigInteger(1, buffer); + // x + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger x = new BigInteger(1, buffer); + return new GnuDHPrivateKey(q, p, g, x); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairX509Codec.java b/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairX509Codec.java new file mode 100644 index 000000000..893716eef --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairX509Codec.java @@ -0,0 +1,255 @@ +/* DHKeyPairX509Codec.java -- X.509 DER encoder/decoder for DH keys + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.dh; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidParameterException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.ArrayList; + +import gnu.java.security.OID; +import gnu.java.security.Registry; +import gnu.java.security.der.BitString; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.der.DERWriter; +import gnu.java.security.key.IKeyPairCodec; +import gnu.java.security.util.DerUtil; + +public class DHKeyPairX509Codec + implements IKeyPairCodec +{ + private static final OID DH_ALG_OID = new OID(Registry.DH_OID_STRING); + + // implicit 0-arguments constructor + + public int getFormatID() + { + return X509_FORMAT; + } + + /** + * Returns the DER-encoded form of the X.509 ASN.1 SubjectPublicKeyInfo + * representation of a DH public key. The ASN.1 specification, as defined in + * RFC-3280, and RFC-2459, is as follows: + * + *
+   *   SubjectPublicKeyInfo ::= SEQUENCE {
+   *     algorithm         AlgorithmIdentifier,
+   *     subjectPublicKey  BIT STRING
+   *   }
+   *
+   *   AlgorithmIdentifier ::= SEQUENCE {
+   *     algorithm   OBJECT IDENTIFIER,
+   *     parameters  ANY DEFINED BY algorithm OPTIONAL
+   *   }
+   *
+   *   DhParams ::= SEQUENCE {
+   *     p  INTEGER, -- odd prime, p=jq +1
+   *     g  INTEGER, -- generator, g
+   *     q  INTEGER  -- factor of p-1
+   *   }
+   * 
+ * + *

The subjectPublicKey field, which is a BIT STRING, contains the + * DER-encoded form of the DH public key as an INTEGER.

+ * + *
+   *       DHPublicKey ::= INTEGER -- public key, y = g^x mod p
+   * 
+ *

+ * IMPORTANT: with RI's {@link javax.crypto.spec.DHGenParameterSpec} + * and {@link javax.crypto.spec.DHParameterSpec} classes, we may end up with + * Diffie-Hellman keys that have a null for the q + * parameter. RFC-2631 DOES NOT allow for an optional value for that + * parameter, hence we replace such null values with 0, and do + * the reverse in the corresponding decode method. + * + * @param key the {@link PublicKey} instance to encode. MUST be an instance of + * {@link GnuDHPublicKey}. + * @return the DER-encoded form of the ASN.1 representation of the + * SubjectPublicKeyInfo in an X.509 certificate. + * @throw InvalidParameterException if key is not an instance + * of {@link GnuDHPublicKey} or if an exception occurs during the + * marshalling process. + */ + public byte[] encodePublicKey(PublicKey key) + { + if (! (key instanceof GnuDHPublicKey)) + throw new InvalidParameterException("Wrong key type"); + + DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DH_ALG_OID); + + GnuDHPublicKey dhKey = (GnuDHPublicKey) key; + BigInteger p = dhKey.getParams().getP(); + BigInteger g = dhKey.getParams().getG(); + BigInteger q = dhKey.getQ(); + if (q == null) + q = BigInteger.ZERO; + BigInteger y = dhKey.getY(); + + DERValue derP = new DERValue(DER.INTEGER, p); + DERValue derG = new DERValue(DER.INTEGER, g); + DERValue derQ = new DERValue(DER.INTEGER, q); + + ArrayList params = new ArrayList(3); + params.add(derP); + params.add(derG); + params.add(derQ); + DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params); + + ArrayList algorithmID = new ArrayList(2); + algorithmID.add(derOID); + algorithmID.add(derParams); + DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + algorithmID); + + DERValue derDHPublicKey = new DERValue(DER.INTEGER, y); + byte[] yBytes = derDHPublicKey.getEncoded(); + DERValue derSPK = new DERValue(DER.BIT_STRING, new BitString(yBytes)); + + ArrayList spki = new ArrayList(2); + spki.add(derAlgorithmID); + spki.add(derSPK); + DERValue derSPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, spki); + + byte[] result; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try + { + DERWriter.write(baos, derSPKI); + result = baos.toByteArray(); + } + catch (IOException x) + { + InvalidParameterException e = new InvalidParameterException(); + e.initCause(x); + throw e; + } + + return result; + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public byte[] encodePrivateKey(PrivateKey key) + { + throw new InvalidParameterException("Wrong format for private keys"); + } + + /** + * @param input the byte array to unmarshall into a valid DH + * {@link PublicKey} instance. MUST NOT be null. + * @return a new instance of a {@link GnuDHPublicKey} decoded from the + * SubjectPublicKeyInfo material in an X.509 certificate. + * @throw InvalidParameterException if an exception occurs during the + * unmarshalling process. + */ + public PublicKey decodePublicKey(byte[] input) + { + if (input == null) + throw new InvalidParameterException("Input bytes MUST NOT be null"); + + BigInteger p, g, q, y; + DERReader der = new DERReader(input); + try + { + DERValue derSPKI = der.read(); + DerUtil.checkIsConstructed(derSPKI, "Wrong SubjectPublicKeyInfo field"); + + DERValue derAlgorithmID = der.read(); + DerUtil.checkIsConstructed(derAlgorithmID, "Wrong AlgorithmIdentifier field"); + + DERValue derOID = der.read(); + if (! (derOID.getValue() instanceof OID)) + throw new InvalidParameterException("Wrong Algorithm field"); + + OID algOID = (OID) derOID.getValue(); + if (! algOID.equals(DH_ALG_OID)) + throw new InvalidParameterException("Unexpected OID: " + algOID); + + DERValue derParams = der.read(); + DerUtil.checkIsConstructed(derParams, "Wrong DH Parameters field"); + + DERValue val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong P field"); + p = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong G field"); + g = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong Q field"); + q = (BigInteger) val.getValue(); + if (q.compareTo(BigInteger.ZERO) == 0) + q = null; + + val = der.read(); + if (! (val.getValue() instanceof BitString)) + throw new InvalidParameterException("Wrong SubjectPublicKey field"); + + byte[] yBytes = ((BitString) val.getValue()).toByteArray(); + + DERReader dhPub = new DERReader(yBytes); + val = dhPub.read(); + DerUtil.checkIsBigInteger(val, "Wrong Y field"); + y = (BigInteger) val.getValue(); + } + catch (IOException x) + { + InvalidParameterException e = new InvalidParameterException(); + e.initCause(x); + throw e; + } + + return new GnuDHPublicKey(Registry.X509_ENCODING_ID, q, p, g, y); + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public PrivateKey decodePrivateKey(byte[] input) + { + throw new InvalidParameterException("Wrong format for private keys"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanKeyAgreement.java b/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanKeyAgreement.java new file mode 100644 index 000000000..893d84d32 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanKeyAgreement.java @@ -0,0 +1,119 @@ +/* DiffieHellmanKeyAgreement.java -- + Copyright (C) 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.crypto.key.dh; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import gnu.javax.crypto.key.BaseKeyAgreementParty; +import gnu.javax.crypto.key.KeyAgreementException; + +import java.math.BigInteger; + +import javax.crypto.interfaces.DHPrivateKey; + +/** + * The basic version of the Diffie-Hellman key agreement is described in the + * Handbook of Applied Cryptography [HAC] as follows: + *

+ *

+ * RFC-2631 describes a Static-Static Mode of operations with + * Diffie-Hellman keypairs as follows: + *

+ *  "In Static-Static mode, both the sender and the recipient have a
+ *  static (and certified) key pair. Since the sender's and recipient's
+ *  keys are therefore the same for each message, ZZ will be the same for
+ *  each message. Thus, partyAInfo MUST be used (and different for each
+ *  message) in order to ensure that different messages use different
+ *  KEKs. Implementations MAY implement Static-Static mode."
+ * 
+ * + *

+ * Reference: + *

    + *
  1. Diffie-Hellman Key + * Agreement Method
    + * Eric Rescorla.
  2. + *
  3. [HAC]: Handbook of + * Applied Cryptography.
    + * CRC Press, Inc. ISBN 0-8493-8523-7, 1997
    + * Menezes, A., van Oorschot, P. and S. Vanstone.
  4. + *
+ */ +public abstract class DiffieHellmanKeyAgreement + extends BaseKeyAgreementParty +{ + public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.dh.ka.prng"; + public static final String KA_DIFFIE_HELLMAN_OWNER_PRIVATE_KEY = + "gnu.crypto.dh.ka.owner.private.key"; + /** The key agreement party's private key. */ + protected DHPrivateKey ownerKey; + /** The shared secret key. */ + protected BigInteger ZZ; + + protected DiffieHellmanKeyAgreement() + { + super(Registry.DH_KA); + } + + protected byte[] engineSharedSecret() throws KeyAgreementException + { + return Util.trim(ZZ); + } + + protected void engineReset() + { + ownerKey = null; + ZZ = null; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java b/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java new file mode 100644 index 000000000..3194f682d --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java @@ -0,0 +1,117 @@ +/* DiffieHellmanReceiver.java -- + Copyright (C) 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.crypto.key.dh; + +import gnu.java.security.prng.IRandom; + +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.OutgoingMessage; + +import java.math.BigInteger; +import java.security.SecureRandom; +import java.util.Map; + +import javax.crypto.interfaces.DHPrivateKey; + +/** + * This implementation is the receiver's part of the basic version of the + * Diffie-Hellman key agreement exchange (B in [HAC]). + * + * @see DiffieHellmanKeyAgreement + */ +public class DiffieHellmanReceiver + extends DiffieHellmanKeyAgreement +{ + private BigInteger y; // the receiver's random secret + + // default 0-arguments constructor + + protected void engineInit(Map attributes) throws KeyAgreementException + { + Object random = attributes.get(SOURCE_OF_RANDOMNESS); + rnd = null; + irnd = null; + if (random instanceof SecureRandom) + rnd = (SecureRandom) random; + else if (random instanceof IRandom) + irnd = (IRandom) random; + ownerKey = (DHPrivateKey) attributes.get(KA_DIFFIE_HELLMAN_OWNER_PRIVATE_KEY); + if (ownerKey == null) + throw new KeyAgreementException("missing owner's private key"); + } + + protected OutgoingMessage engineProcessMessage(IncomingMessage in) + throws KeyAgreementException + { + switch (step) + { + case 0: + return computeSharedSecret(in); + default: + throw new IllegalStateException("unexpected state"); + } + } + + private OutgoingMessage computeSharedSecret(IncomingMessage in) + throws KeyAgreementException + { + BigInteger m1 = in.readMPI(); + if (m1 == null) + throw new KeyAgreementException("missing message (1)"); + BigInteger p = ownerKey.getParams().getP(); + BigInteger g = ownerKey.getParams().getG(); + // B chooses a random integer y, 1 <= y <= p-2 + // rfc-2631 restricts y to only be in [2, p-1] + BigInteger p_minus_2 = p.subtract(TWO); + byte[] xBytes = new byte[(p_minus_2.bitLength() + 7) / 8]; + do + { + nextRandomBytes(xBytes); + y = new BigInteger(1, xBytes); + } + while (! (y.compareTo(TWO) >= 0 && y.compareTo(p_minus_2) <= 0)); + ZZ = m1.modPow(y, p); // ZZ = (yb ^ xa) mod p + complete = true; + // B sends A the message: g^y mod p + OutgoingMessage result = new OutgoingMessage(); + result.writeMPI(g.modPow(y, p)); // message (2) + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanSender.java b/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanSender.java new file mode 100644 index 000000000..7fc997354 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanSender.java @@ -0,0 +1,126 @@ +/* DiffieHellmanSender.java -- + Copyright (C) 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.crypto.key.dh; + +import gnu.java.security.prng.IRandom; + +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.OutgoingMessage; + +import java.math.BigInteger; +import java.security.SecureRandom; +import java.util.Map; + +import javax.crypto.interfaces.DHPrivateKey; + +/** + * This implementation is the sender's part of the basic version of the + * Diffie-Hellman key agreement exchange (A in [HAC]). + * + * @see DiffieHellmanKeyAgreement + */ +public class DiffieHellmanSender + extends DiffieHellmanKeyAgreement +{ + private BigInteger x; // the sender's random secret + + // default 0-arguments constructor + + protected void engineInit(Map attributes) throws KeyAgreementException + { + Object random = attributes.get(SOURCE_OF_RANDOMNESS); + rnd = null; + irnd = null; + if (random instanceof SecureRandom) + rnd = (SecureRandom) random; + else if (random instanceof IRandom) + irnd = (IRandom) random; + ownerKey = (DHPrivateKey) attributes.get(KA_DIFFIE_HELLMAN_OWNER_PRIVATE_KEY); + if (ownerKey == null) + throw new KeyAgreementException("missing owner's private key"); + } + + protected OutgoingMessage engineProcessMessage(IncomingMessage in) + throws KeyAgreementException + { + switch (step) + { + case 0: + return sendRandomSecret(in); + case 1: + return computeSharedSecret(in); + default: + throw new IllegalStateException("unexpected state"); + } + } + + private OutgoingMessage sendRandomSecret(IncomingMessage in) + throws KeyAgreementException + { + BigInteger p = ownerKey.getParams().getP(); + BigInteger g = ownerKey.getParams().getG(); + // A chooses a random integer x, 1 <= x <= p-2 + // rfc-2631 restricts x to only be in [2, p-1] + BigInteger p_minus_2 = p.subtract(TWO); + byte[] xBytes = new byte[(p_minus_2.bitLength() + 7) / 8]; + do + { + nextRandomBytes(xBytes); + x = new BigInteger(1, xBytes); + } + while (! (x.compareTo(TWO) >= 0 && x.compareTo(p_minus_2) <= 0)); + // A sends B the message: g^x mod p + OutgoingMessage result = new OutgoingMessage(); + result.writeMPI(g.modPow(x, p)); + return result; + } + + private OutgoingMessage computeSharedSecret(IncomingMessage in) + throws KeyAgreementException + { + BigInteger m1 = in.readMPI(); + if (m1 == null) + throw new KeyAgreementException("missing message (2)"); + BigInteger p = ownerKey.getParams().getP(); + ZZ = m1.modPow(x, p); // ZZ = (yb ^ xa) mod p + complete = true; + return null; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java b/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java new file mode 100644 index 000000000..4283dc59b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java @@ -0,0 +1,115 @@ +/* ElGamalKeyAgreement.java -- + Copyright (C) 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.crypto.key.dh; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import gnu.javax.crypto.key.BaseKeyAgreementParty; +import gnu.javax.crypto.key.KeyAgreementException; + +import java.math.BigInteger; + +/** + * The ElGamal key agreement, also known as the half-certified Diffie-Hellman + * key agreement, is described in the Handbook of Applied Cryptography [HAC] as + * follows: + * + *

+ * RFC-2631 describes an Ephemeral-Static Mode of operations with + * Diffie-Hellman keypairs as follows: + *

+ *  "In Ephemeral-Static mode, the recipient has a static (and certified)
+ *  key pair, but the sender generates a new key pair for each message
+ *  and sends it using the originatorKey production. If the sender's key
+ *  is freshly generated for each message, the shared secret ZZ will be
+ *  similarly different for each message and partyAInfo MAY be omitted,
+ *  since it serves merely to decouple multiple KEKs generated by the
+ *  same set of pairwise keys. If, however, the same ephemeral sender key
+ *  is used for multiple messages (e.g. it is cached as a performance
+ *  optimization) then a separate partyAInfo MUST be used for each
+ *  message. All implementations of this standard MUST implement
+ *  Ephemeral-Static mode."
+ * 
+ *

+ * Reference: + *

    + *
  1. Diffie-Hellman Key + * Agreement Method
    + * Eric Rescorla.
  2. + *
  3. [HAC]: Handbook of + * Applied Cryptography.
    + * CRC Press, Inc. ISBN 0-8493-8523-7, 1997
    + * Menezes, A., van Oorschot, P. and S. Vanstone.
  4. + *
+ */ +public abstract class ElGamalKeyAgreement + extends BaseKeyAgreementParty +{ + public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.elgamal.ka.prng"; + public static final String KA_ELGAMAL_RECIPIENT_PRIVATE_KEY = + "gnu.crypto.elgamal.ka.recipient.private.key"; + public static final String KA_ELGAMAL_RECIPIENT_PUBLIC_KEY = + "gnu.crypto.elgamal.ka.recipient.public.key"; + /** The shared secret key. */ + protected BigInteger ZZ; + + protected ElGamalKeyAgreement() + { + super(Registry.ELGAMAL_KA); + } + + protected byte[] engineSharedSecret() throws KeyAgreementException + { + return Util.trim(ZZ); + } + + protected void engineReset() + { + ZZ = null; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalReceiver.java b/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalReceiver.java new file mode 100644 index 000000000..ad606f6c9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalReceiver.java @@ -0,0 +1,99 @@ +/* ElGamalReceiver.java -- + Copyright (C) 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.crypto.key.dh; + +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.OutgoingMessage; + +import java.math.BigInteger; +import java.security.SecureRandom; +import java.util.Map; + +import javax.crypto.interfaces.DHPrivateKey; + +/** + * This implementation is the receiver's part of the ElGamal key agreement + * exchange (B in [HAC]). + * + * @see ElGamalKeyAgreement + */ +public class ElGamalReceiver + extends ElGamalKeyAgreement +{ + /** The recipient's private key. */ + private DHPrivateKey B; + + // default 0-arguments constructor + + protected void engineInit(Map attributes) throws KeyAgreementException + { + rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS); + // One-time setup (key generation and publication). Each user B generates + // a keypair and publishes its public key + B = (DHPrivateKey) attributes.get(KA_ELGAMAL_RECIPIENT_PRIVATE_KEY); + if (B == null) + throw new KeyAgreementException("missing recipient private key"); + } + + protected OutgoingMessage engineProcessMessage(IncomingMessage in) + throws KeyAgreementException + { + switch (step) + { + case 0: + return computeSharedSecret(in); + default: + throw new IllegalStateException("unexpected state"); + } + } + + private OutgoingMessage computeSharedSecret(IncomingMessage in) + throws KeyAgreementException + { + // (b) B computes the same key on receipt of message (1) as + // K = (g^x)^xb mod p + BigInteger m1 = in.readMPI(); + if (m1 == null) + throw new KeyAgreementException("missing message (1)"); + ZZ = m1.modPow(B.getX(), B.getParams().getP()); // ZZ = (ya ^ xb) mod p + complete = true; + return null; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalSender.java b/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalSender.java new file mode 100644 index 000000000..bc9643500 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalSender.java @@ -0,0 +1,112 @@ +/* ElGamalSender.java -- + Copyright (C) 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.crypto.key.dh; + +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.OutgoingMessage; + +import java.math.BigInteger; +import java.security.SecureRandom; +import java.util.Map; + +import javax.crypto.interfaces.DHPublicKey; + +/** + * This implementation is the sender's part of the ElGamal key agreement + * exchange (A in [HAC]). + * + * @see ElGamalKeyAgreement + */ +public class ElGamalSender + extends ElGamalKeyAgreement +{ + /** The recipient's public key. */ + private DHPublicKey B; + + // default 0-arguments constructor + + protected void engineInit(Map attributes) throws KeyAgreementException + { + rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS); + // One-time setup (key generation and publication). Each user B generates + // a keypair and publishes its public key + B = (DHPublicKey) attributes.get(KA_ELGAMAL_RECIPIENT_PUBLIC_KEY); + if (B == null) + throw new KeyAgreementException("missing recipient public key"); + } + + protected OutgoingMessage engineProcessMessage(IncomingMessage in) + throws KeyAgreementException + { + switch (step) + { + case 0: + return computeSharedSecret(in); + default: + throw new IllegalStateException("unexpected state"); + } + } + + private OutgoingMessage computeSharedSecret(IncomingMessage in) + throws KeyAgreementException + { + BigInteger p = B.getParams().getP(); + BigInteger g = B.getParams().getG(); + BigInteger yb = B.getY(); + // A chooses a random integer x, 1 <= x <= p-2 + // rfc-2631 restricts x to only be in [2, p-1] + BigInteger p_minus_2 = p.subtract(TWO); + byte[] xBytes = new byte[(p_minus_2.bitLength() + 7) / 8]; + BigInteger x; + do + { + nextRandomBytes(xBytes); + x = new BigInteger(1, xBytes); + } + while (x.compareTo(TWO) >= 0 && x.compareTo(p_minus_2) <= 0); + // A sends B the message: g^x mod p + OutgoingMessage result = new OutgoingMessage(); + result.writeMPI(g.modPow(x, p)); + // A computes the key as K = (yb)^x mod p + ZZ = yb.modPow(x, p); // ZZ = (yb ^ xa) mod p + complete = true; + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKey.java b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKey.java new file mode 100644 index 000000000..03a18c310 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKey.java @@ -0,0 +1,174 @@ +/* GnuDHKey.java -- + Copyright (C) 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.crypto.key.dh; + +import gnu.java.security.Registry; +import gnu.java.security.action.GetPropertyAction; +import gnu.java.security.util.FormatUtil; + +import java.math.BigInteger; +import java.security.AccessController; +import java.security.Key; + +import javax.crypto.interfaces.DHKey; +import javax.crypto.spec.DHParameterSpec; + +/** + * A base asbtract class for both public and private Diffie-Hellman keys. It + * encapsulates the two DH numbers: p, and g. + *

+ * According to the JDK, cryptographic Keys all have a format. + * The format used in this implementation is called Raw, and basically + * consists of the raw byte sequences of algorithm parameters. The exact order + * of the byte sequences and the implementation details are given in each of the + * relevant getEncoded() methods of each of the private and + * public keys. + *

+ * Reference: + *

    + *
  1. Diffie-Hellman Key + * Agreement Method
    + * Eric Rescorla.
  2. + *
+ */ +public abstract class GnuDHKey + implements Key, DHKey +{ + /** The public prime q. A prime divisor of p-1. */ + protected BigInteger q; + /** The public prime p. */ + protected BigInteger p; + /** The generator g. */ + protected BigInteger g; + /** + * Identifier of the default encoding format to use when externalizing the key + * material. + */ + protected final int defaultFormat; + /** String representation of this key. Cached for speed. */ + private transient String str; + + /** + * Trivial protected constructor. + * + * @param defaultFormat the identifier of the encoding format to use by + * default when externalizing the key. + * @param q a prime divisor of p-1. + * @param p the public prime. + * @param g the generator of the group. + */ + protected GnuDHKey(int defaultFormat, BigInteger q, BigInteger p, BigInteger g) + { + super(); + + this.defaultFormat = defaultFormat <= 0 ? Registry.RAW_ENCODING_ID + : defaultFormat; + this.q = q; + this.p = p; + this.g = g; + } + + public DHParameterSpec getParams() + { + if (q == null) + return new DHParameterSpec(p, g); + return new DHParameterSpec(p, g, q.bitLength()); + } + + public String getAlgorithm() + { + return Registry.DH_KPG; + } + + /** @deprecated see getEncoded(int). */ + public byte[] getEncoded() + { + return getEncoded(defaultFormat); + } + + public String getFormat() + { + return FormatUtil.getEncodingShortName(defaultFormat); + } + + public BigInteger getQ() + { + return q; + } + + /** + * Returns true if the designated object is an instance of + * {@link DHKey} and has the same Diffie-Hellman parameter values as this one. + * + * @param obj the other non-null DH key to compare to. + * @return true if the designated object is of the same type + * and value as this one. + */ + public boolean equals(Object obj) + { + if (obj == null) + return false; + if (! (obj instanceof DHKey)) + return false; + DHKey that = (DHKey) obj; + return p.equals(that.getParams().getP()) + && g.equals(that.getParams().getG()); + } + + public String toString() + { + if (str == null) + { + String ls = (String) AccessController.doPrivileged + (new GetPropertyAction("line.separator")); + StringBuilder sb = new StringBuilder(ls) + .append("defaultFormat=").append(defaultFormat).append(",").append(ls); + if (q == null) + sb.append("q=null,"); + else + sb.append("q=0x").append(q.toString(16)).append(","); + sb.append(ls).append("p=0x").append(p.toString(16)).append(",").append(ls) + .append("g=0x").append(g.toString(16)); + str = sb.toString(); + } + return str; + } + + public abstract byte[] getEncoded(int format); +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java new file mode 100644 index 000000000..89e9c4c80 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java @@ -0,0 +1,235 @@ +/* GnuDHKeyPairGenerator.java -- + Copyright (C) 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.crypto.key.dh; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.hash.Sha160; +import gnu.java.security.key.IKeyPairGenerator; +import gnu.java.security.util.PRNG; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.util.Map; +import java.util.logging.Logger; + +import javax.crypto.spec.DHGenParameterSpec; +import javax.crypto.spec.DHParameterSpec; + +/** + * An implementation of a Diffie-Hellman keypair generator. + *

+ * Reference: + *

    + *
  1. Diffie-Hellman Key + * Agreement Method
    + * Eric Rescorla.
  2. + *
+ */ +public class GnuDHKeyPairGenerator + implements IKeyPairGenerator +{ + private static final Logger log = Logger.getLogger(GnuDHKeyPairGenerator.class.getName()); + /** + * Property name of an optional {@link SecureRandom} instance to use. The + * default is to use a classloader singleton from {@link PRNG}. + */ + public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.dh.prng"; + /** + * Property name of an optional {@link DHGenParameterSpec} or + * {@link DHParameterSpec} instance to use for this generator. + */ + public static final String DH_PARAMETERS = "gnu.crypto.dh.params"; + /** Property name of the size in bits (Integer) of the public prime (p). */ + public static final String PRIME_SIZE = "gnu.crypto.dh.L"; + /** Property name of the size in bits (Integer) of the private exponent (x). */ + public static final String EXPONENT_SIZE = "gnu.crypto.dh.m"; + /** + * Property name of the preferred encoding format to use when externalizing + * generated instance of key-pairs from this generator. The property is taken + * to be an {@link Integer} that encapsulates an encoding format identifier. + */ + public static final String PREFERRED_ENCODING_FORMAT = "gnu.crypto.dh.encoding"; + /** Default value for the size in bits of the public prime (p). */ + public static final int DEFAULT_PRIME_SIZE = 512; + /** Default value for the size in bits of the private exponent (x). */ + public static final int DEFAULT_EXPONENT_SIZE = 160; + /** Default encoding format to use when none was specified. */ + private static final int DEFAULT_ENCODING_FORMAT = Registry.RAW_ENCODING_ID; + /** The SHA instance to use. */ + private Sha160 sha = new Sha160(); + /** The optional {@link SecureRandom} instance to use. */ + private SecureRandom rnd = null; + /** The desired size in bits of the public prime (p). */ + private int l; + /** The desired size in bits of the private exponent (x). */ + private int m; + private BigInteger seed; + private BigInteger counter; + private BigInteger q; + private BigInteger p; + private BigInteger j; + private BigInteger g; + /** Our default source of randomness. */ + private PRNG prng = null; + /** Preferred encoding format of generated keys. */ + private int preferredFormat; + + // default 0-arguments constructor + + public String name() + { + return Registry.DH_KPG; + } + + public void setup(Map attributes) + { + // do we have a SecureRandom, or should we use our own? + rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS); + // are we given a set of Diffie-Hellman generation parameters or we shall + // use our own? + Object params = attributes.get(DH_PARAMETERS); + // find out the desired sizes + if (params instanceof DHGenParameterSpec) + { + DHGenParameterSpec jceSpec = (DHGenParameterSpec) params; + l = jceSpec.getPrimeSize(); + m = jceSpec.getExponentSize(); + } + else if (params instanceof DHParameterSpec) + { + // FIXME: I'm not sure this is correct. It seems to behave the + // same way as Sun's RI, but I don't know if this behavior is + // documented anywhere. + DHParameterSpec jceSpec = (DHParameterSpec) params; + p = jceSpec.getP(); + g = jceSpec.getG(); + l = p.bitLength(); + m = jceSpec.getL(); + // If no exponent size was given, generate an exponent as + // large as the prime. + if (m == 0) + m = l; + } + else + { + Integer bi = (Integer) attributes.get(PRIME_SIZE); + l = (bi == null ? DEFAULT_PRIME_SIZE : bi.intValue()); + bi = (Integer) attributes.get(EXPONENT_SIZE); + m = (bi == null ? DEFAULT_EXPONENT_SIZE : bi.intValue()); + } + if ((l % 256) != 0 || l < DEFAULT_PRIME_SIZE) + throw new IllegalArgumentException("invalid modulus size"); + if ((m % 8) != 0 || m < DEFAULT_EXPONENT_SIZE) + throw new IllegalArgumentException("invalid exponent size"); + if (m > l) + throw new IllegalArgumentException("exponent size > modulus size"); + // what is the preferred encoding format + Integer formatID = (Integer) attributes.get(PREFERRED_ENCODING_FORMAT); + preferredFormat = formatID == null ? DEFAULT_ENCODING_FORMAT + : formatID.intValue(); + } + + public KeyPair generate() + { + if (p == null) + { + BigInteger[] params = new RFC2631(m, l, rnd).generateParameters(); + seed = params[RFC2631.DH_PARAMS_SEED]; + counter = params[RFC2631.DH_PARAMS_COUNTER]; + q = params[RFC2631.DH_PARAMS_Q]; + p = params[RFC2631.DH_PARAMS_P]; + j = params[RFC2631.DH_PARAMS_J]; + g = params[RFC2631.DH_PARAMS_G]; + if (Configuration.DEBUG) + { + log.fine("seed: 0x" + seed.toString(16)); + log.fine("counter: " + counter.intValue()); + log.fine("q: 0x" + q.toString(16)); + log.fine("p: 0x" + p.toString(16)); + log.fine("j: 0x" + j.toString(16)); + log.fine("g: 0x" + g.toString(16)); + } + } + // generate a private number x of length m such as: 1 < x < q - 1 + BigInteger q_minus_1 = null; + if (q != null) + q_minus_1 = q.subtract(BigInteger.ONE); + // We already check if m is modulo 8 in `setup.' This could just + // be m >>> 3. + byte[] mag = new byte[(m + 7) / 8]; + BigInteger x; + while (true) + { + nextRandomBytes(mag); + x = new BigInteger(1, mag); + if (x.bitLength() == m && x.compareTo(BigInteger.ONE) > 0 + && (q_minus_1 == null || x.compareTo(q_minus_1) < 0)) + break; + } + BigInteger y = g.modPow(x, p); + PrivateKey secK = new GnuDHPrivateKey(preferredFormat, q, p, g, x); + PublicKey pubK = new GnuDHPublicKey(preferredFormat, q, p, g, y); + return new KeyPair(pubK, secK); + } + + /** + * Fills the designated byte array with random data. + * + * @param buffer the byte array to fill with random data. + */ + private void nextRandomBytes(byte[] buffer) + { + if (rnd != null) + rnd.nextBytes(buffer); + else + getDefaultPRNG().nextBytes(buffer); + } + + private PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + + return prng; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPrivateKey.java b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPrivateKey.java new file mode 100644 index 000000000..881421a74 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPrivateKey.java @@ -0,0 +1,200 @@ +/* GnuDHPrivateKey.java -- + Copyright (C) 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.crypto.key.dh; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.action.GetPropertyAction; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.AccessController; + +import javax.crypto.interfaces.DHPrivateKey; + +/** + * An implementation of the Diffie-Hellman private key. + *

+ * Reference: + *

    + *
  1. Diffie-Hellman Key + * Agreement Method
    + * Eric Rescorla.
  2. + *
+ */ +public class GnuDHPrivateKey + extends GnuDHKey + implements DHPrivateKey +{ + /** The private exponent. */ + private final BigInteger x; + /** String representation of this key. Cached for speed. */ + private transient String str; + + /** + * Convenience constructor. Calls the constructor with five arguments passing + * {@link Registry#RAW_ENCODING_ID} as the value of its first argument. + * + * @param q a prime divisor of p-1. + * @param p the public prime. + * @param g the generator of the group. + * @param x the private value x. + */ + public GnuDHPrivateKey(BigInteger q, BigInteger p, BigInteger g, BigInteger x) + { + this(Registry.RAW_ENCODING_ID, q, p, g, x); + } + + /** + * Constructs a new instance of GnuDHPrivateKey given the + * designated parameters. + * + * @param preferredFormat the identifier of the encoding format to use by + * default when externalizing the key. + * @param q a prime divisor of p-1. + * @param p the public prime. + * @param g the generator of the group. + * @param x the private value x. + */ + public GnuDHPrivateKey(int preferredFormat, BigInteger q, BigInteger p, + BigInteger g, BigInteger x) + { + super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.PKCS8_ENCODING_ID + : preferredFormat, + q, p, g); + this.x = x; + } + + /** + * A class method that takes the output of the encodePrivateKey() + * method of a DH keypair codec object (an instance implementing + * {@link IKeyPairCodec} for DH keys, and re-constructs an instance of this + * object. + * + * @param k the contents of a previously encoded instance of this object. + * @exception ArrayIndexOutOfBoundsException if there is not enough bytes, in + * k, to represent a valid encoding of an + * instance of this object. + * @exception IllegalArgumentException if the byte sequence does not represent + * a valid encoding of an instance of this object. + */ + public static GnuDHPrivateKey valueOf(byte[] k) + { + // try RAW codec + if (k[0] == Registry.MAGIC_RAW_DH_PRIVATE_KEY[0]) + try + { + return (GnuDHPrivateKey) new DHKeyPairRawCodec().decodePrivateKey(k); + } + catch (IllegalArgumentException ignored) + { + } + // try PKCS#8 codec + return (GnuDHPrivateKey) new DHKeyPairPKCS8Codec().decodePrivateKey(k); + } + + public BigInteger getX() + { + return x; + } + + /** + * Returns the encoded form of this private key according to the designated + * format. + * + * @param format the desired format identifier of the resulting encoding. + * @return the byte sequence encoding this key according to the designated + * format. + * @exception IllegalArgumentException if the format is not supported. + * @see DHKeyPairRawCodec + */ + public byte[] getEncoded(int format) + { + byte[] result; + switch (format) + { + case IKeyPairCodec.RAW_FORMAT: + result = new DHKeyPairRawCodec().encodePrivateKey(this); + break; + case IKeyPairCodec.PKCS8_FORMAT: + result = new DHKeyPairPKCS8Codec().encodePrivateKey(this); + break; + default: + throw new IllegalArgumentException("Unsupported encoding format: " + + format); + } + return result; + } + + /** + * Returns true if the designated object is an instance of + * {@link DHPrivateKey} and has the same parameter values as this one. + * + * @param obj the other non-null DH key to compare to. + * @return true if the designated object is of the same type + * and value as this one. + */ + public boolean equals(Object obj) + { + if (obj == null) + return false; + + if (! (obj instanceof DHPrivateKey)) + return false; + + DHPrivateKey that = (DHPrivateKey) obj; + return super.equals(that) && x.equals(that.getX()); + } + + public String toString() + { + if (str == null) + { + String ls = (String) AccessController.doPrivileged + (new GetPropertyAction("line.separator")); + str = new StringBuilder(this.getClass().getName()).append("(") + .append(super.toString()).append(",").append(ls) + .append("x=0x").append(Configuration.DEBUG ? x.toString(16) + : "**...*").append(ls) + .append(")") + .toString(); + } + return str; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPublicKey.java b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPublicKey.java new file mode 100644 index 000000000..5f1771bb0 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPublicKey.java @@ -0,0 +1,196 @@ +/* GnuDHPublicKey.java -- + Copyright (C) 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.crypto.key.dh; + +import gnu.java.security.Registry; +import gnu.java.security.action.GetPropertyAction; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.AccessController; + +import javax.crypto.interfaces.DHPublicKey; + +/** + * An implementation of the Diffie-Hellman public key. + *

+ * Reference: + *

    + *
  1. Diffie-Hellman Key + * Agreement Method
    + * Eric Rescorla.
  2. + *
+ */ +public class GnuDHPublicKey + extends GnuDHKey + implements DHPublicKey +{ + private BigInteger y; + /** String representation of this key. Cached for speed. */ + private transient String str; + + /** + * Convenience constructor. Calls the constructor with five arguments passing + * {@link Registry#RAW_ENCODING_ID} as the value of its first argument. + * + * @param q a prime divisor of p-1. + * @param p the public prime. + * @param g the generator of the group. + * @param y the public value y. + */ + public GnuDHPublicKey(BigInteger q, BigInteger p, BigInteger g, BigInteger y) + { + this(Registry.RAW_ENCODING_ID, q, p, g, y); + } + + /** + * Constructs a new instance of GnuDHPublicKey given the + * designated parameters. + * + * @param preferredFormat the identifier of the encoding format to use by + * default when externalizing the key. + * @param q a prime divisor of p-1. + * @param p the public prime. + * @param g the generator of the group. + * @param y the public value y. + */ + public GnuDHPublicKey(int preferredFormat, BigInteger q, BigInteger p, + BigInteger g, BigInteger y) + { + super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.X509_ENCODING_ID + : preferredFormat, + q, p, g); + this.y = y; + } + + /** + * A class method that takes the output of the encodePublicKey() + * method of a DH keypair codec object (an instance implementing + * {@link IKeyPairCodec} for DSS keys, and re-constructs an instance of this + * object. + * + * @param k the contents of a previously encoded instance of this object. + * @exception ArrayIndexOutOfBoundsException if there is not enough bytes, in + * k, to represent a valid encoding of an + * instance of this object. + * @exception IllegalArgumentException if the byte sequence does not represent + * a valid encoding of an instance of this object. + */ + public static GnuDHPublicKey valueOf(byte[] k) + { + // try RAW codec + if (k[0] == Registry.MAGIC_RAW_DH_PUBLIC_KEY[0]) + try + { + return (GnuDHPublicKey) new DHKeyPairRawCodec().decodePublicKey(k); + } + catch (IllegalArgumentException ignored) + { + } + // try X.509 codec + return (GnuDHPublicKey) new DHKeyPairX509Codec().decodePublicKey(k); + } + + public BigInteger getY() + { + return y; + } + + /** + * Returns the encoded form of this public key according to the designated + * format. + * + * @param format the desired format identifier of the resulting encoding. + * @return the byte sequence encoding this key according to the designated + * format. + * @exception IllegalArgumentException if the format is not supported. + */ + public byte[] getEncoded(int format) + { + byte[] result; + switch (format) + { + case IKeyPairCodec.RAW_FORMAT: + result = new DHKeyPairRawCodec().encodePublicKey(this); + break; + case IKeyPairCodec.X509_FORMAT: + result = new DHKeyPairX509Codec().encodePublicKey(this); + break; + default: + throw new IllegalArgumentException("Unsupported encoding format: " + + format); + } + return result; + } + + /** + * Returns true if the designated object is an instance of + * {@link DHPublicKey} and has the same parameter values as this one. + * + * @param obj the other non-null DH key to compare to. + * @return true if the designated object is of the same type + * and value as this one. + */ + public boolean equals(Object obj) + { + if (obj == null) + return false; + + if (! (obj instanceof DHPublicKey)) + return false; + + DHPublicKey that = (DHPublicKey) obj; + return super.equals(that) && y.equals(that.getY()); + } + + public String toString() + { + if (str == null) + { + String ls = (String) AccessController.doPrivileged + (new GetPropertyAction("line.separator")); + str = new StringBuilder(this.getClass().getName()).append("(") + .append(super.toString()).append(",").append(ls) + .append("y=0x").append(y.toString(16)).append(ls) + .append(")") + .toString(); + } + return str; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/RFC2631.java b/libjava/classpath/gnu/javax/crypto/key/dh/RFC2631.java new file mode 100644 index 000000000..60ef49409 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/RFC2631.java @@ -0,0 +1,217 @@ +/* RFC2631.java -- + Copyright (C) 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.crypto.key.dh; + +import gnu.java.security.hash.Sha160; +import gnu.java.security.util.PRNG; + +import java.math.BigInteger; +import java.security.SecureRandom; + +/** + * An implementation of the Diffie-Hellman parameter generation as defined in + * RFC-2631. + *

+ * Reference: + *

    + *
  1. Diffie-Hellman Key + * Agreement Method
    + * Eric Rescorla.
  2. + *
+ */ +public class RFC2631 +{ + public static final int DH_PARAMS_SEED = 0; + public static final int DH_PARAMS_COUNTER = 1; + public static final int DH_PARAMS_Q = 2; + public static final int DH_PARAMS_P = 3; + public static final int DH_PARAMS_J = 4; + public static final int DH_PARAMS_G = 5; + private static final BigInteger TWO = BigInteger.valueOf(2L); + /** The SHA instance to use. */ + private Sha160 sha = new Sha160(); + /** Length of private modulus and of q. */ + private int m; + /** Length of public modulus p. */ + private int L; + /** The optional {@link SecureRandom} instance to use. */ + private SecureRandom rnd = null; + /** Our default source of randomness. */ + private PRNG prng = null; + + public RFC2631(int m, int L, SecureRandom rnd) + { + super(); + + this.m = m; + this.L = L; + this.rnd = rnd; + } + + public BigInteger[] generateParameters() + { + int i, j, counter; + byte[] u1, u2, v; + byte[] seedBytes = new byte[m / 8]; + BigInteger SEED, U, q, R, V, W, X, p, g; + // start by genrating p and q, where q is of length m and p is of length L + // 1. Set m' = m/160 where / represents integer division with rounding + // upwards. I.e. 200/160 = 2. + int m_ = (m + 159) / 160; + // 2. Set L'= L/160 + int L_ = (L + 159) / 160; + // 3. Set N'= L/1024 + int N_ = (L + 1023) / 1024; + algorithm: while (true) + { + step4: while (true) + { + // 4. Select an arbitrary bit string SEED such that length of + // SEED >= m + nextRandomBytes(seedBytes); + SEED = new BigInteger(1, seedBytes).setBit(m - 1).setBit(0); + // 5. Set U = 0 + U = BigInteger.ZERO; + // 6. For i = 0 to m' - 1 + // U = U + (SHA1[SEED + i] XOR SHA1[(SEED + m' + i)) * 2^(160 * i) + // Note that for m=160, this reduces to the algorithm of FIPS-186 + // U = SHA1[SEED] XOR SHA1[(SEED+1) mod 2^160 ]. + for (i = 0; i < m_; i++) + { + u1 = SEED.add(BigInteger.valueOf(i)).toByteArray(); + u2 = SEED.add(BigInteger.valueOf(m_ + i)).toByteArray(); + sha.update(u1, 0, u1.length); + u1 = sha.digest(); + sha.update(u2, 0, u2.length); + u2 = sha.digest(); + for (j = 0; j < u1.length; j++) + u1[j] ^= u2[j]; + U = U.add(new BigInteger(1, u1).multiply(TWO.pow(160 * i))); + } + // 5. Form q from U by computing U mod (2^m) and setting the most + // significant bit (the 2^(m-1) bit) and the least significant + // bit to 1. In terms of boolean operations, q = U OR 2^(m-1) OR + // 1. Note that 2^(m-1) < q < 2^m + q = U.setBit(m - 1).setBit(0); + // 6. Use a robust primality algorithm to test whether q is prime. + // 7. If q is not prime then go to 4. + if (q.isProbablePrime(80)) + break step4; + } + // 8. Let counter = 0 + counter = 0; + while (true) + { + // 9. Set R = seed + 2*m' + (L' * counter) + R = SEED + .add(BigInteger.valueOf(2 * m_)) + .add(BigInteger.valueOf(L_ * counter)); + // 10. Set V = 0 + V = BigInteger.ZERO; + // 12. For i = 0 to L'-1 do: V = V + SHA1(R + i) * 2^(160 * i) + for (i = 0; i < L_; i++) + { + v = R.toByteArray(); + sha.update(v, 0, v.length); + v = sha.digest(); + V = V.add(new BigInteger(1, v).multiply(TWO.pow(160 * i))); + } + // 13. Set W = V mod 2^L + W = V.mod(TWO.pow(L)); + // 14. Set X = W OR 2^(L-1) + // Note that 0 <= W < 2^(L-1) and hence X >= 2^(L-1) + X = W.setBit(L - 1); + // 15. Set p = X - (X mod (2*q)) + 1 + p = X.add(BigInteger.ONE).subtract(X.mod(TWO.multiply(q))); + // 16. If p > 2^(L-1) use a robust primality test to test whether p + // is prime. Else go to 18. + // 17. If p is prime output p, q, seed, counter and stop. + if (p.isProbablePrime(80)) + { + break algorithm; + } + // 18. Set counter = counter + 1 + counter++; + // 19. If counter < (4096 * N) then go to 8. + // 20. Output "failure" + if (counter >= 4096 * N_) + continue algorithm; + } + } + // compute g. from FIPS-186, Appendix 4: + // 1. Generate p and q as specified in Appendix 2. + // 2. Let e = (p - 1) / q + BigInteger e = p.subtract(BigInteger.ONE).divide(q); + BigInteger h = TWO; + BigInteger p_minus_1 = p.subtract(BigInteger.ONE); + g = TWO; + // 3. Set h = any integer, where 1 < h < p - 1 and h differs from any + // value previously tried + for (; h.compareTo(p_minus_1) < 0; h = h.add(BigInteger.ONE)) + { + // 4. Set g = h**e mod p + g = h.modPow(e, p); + // 5. If g = 1, go to step 3 + if (! g.equals(BigInteger.ONE)) + break; + } + return new BigInteger[] { SEED, BigInteger.valueOf(counter), q, p, e, g }; + } + + /** + * Fills the designated byte array with random data. + * + * @param buffer the byte array to fill with random data. + */ + private void nextRandomBytes(byte[] buffer) + { + if (rnd != null) + rnd.nextBytes(buffer); + else + getDefaultPRNG().nextBytes(buffer); + } + + private PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + + return prng; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6Host.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6Host.java new file mode 100644 index 000000000..2c8e66fa2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6Host.java @@ -0,0 +1,161 @@ +/* SRP6Host.java -- + Copyright (C) 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.crypto.key.srp6; + +import gnu.java.security.Registry; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.util.Util; +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.OutgoingMessage; +import gnu.javax.crypto.sasl.srp.SRP; +import gnu.javax.crypto.sasl.srp.SRPAuthInfoProvider; +import gnu.javax.crypto.sasl.srp.SRPRegistry; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.SecureRandom; +import java.util.HashMap; +import java.util.Map; + +/** + * The implementation of the Host in the SRP-6 key agreement protocol. + *

+ * Reference: + *

    + *
  1. SRP Protocol Design
    + * Thomas J. Wu.
  2. + *
+ */ +public class SRP6Host + extends SRP6KeyAgreement +{ + /** The user's ephemeral key pair. */ + private KeyPair hostKeyPair; + + /** The SRP password database. */ + private SRPAuthInfoProvider passwordDB; + + // default 0-arguments constructor + + protected void engineInit(final Map attributes) throws KeyAgreementException + { + rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS); + N = (BigInteger) attributes.get(SHARED_MODULUS); + if (N == null) + throw new KeyAgreementException("missing shared modulus"); + g = (BigInteger) attributes.get(GENERATOR); + if (g == null) + throw new KeyAgreementException("missing generator"); + final String md = (String) attributes.get(HASH_FUNCTION); + if (md == null || md.trim().length() == 0) + throw new KeyAgreementException("missing hash function"); + srp = SRP.instance(md); + passwordDB = (SRPAuthInfoProvider) attributes.get(HOST_PASSWORD_DB); + if (passwordDB == null) + throw new KeyAgreementException("missing SRP password database"); + } + + protected OutgoingMessage engineProcessMessage(final IncomingMessage in) + throws KeyAgreementException + { + switch (step) + { + case 0: + return computeSharedSecret(in); + default: + throw new IllegalStateException("unexpected state"); + } + } + + protected void engineReset() + { + hostKeyPair = null; + super.engineReset(); + } + + private OutgoingMessage computeSharedSecret(final IncomingMessage in) + throws KeyAgreementException + { + final String I = in.readString(); + final BigInteger A = in.readMPI(); + // get s and v for user identified by I + // ---------------------------------------------------------------------- + final Map credentials; + try + { + final Map userID = new HashMap(); + userID.put(Registry.SASL_USERNAME, I); + userID.put(SRPRegistry.MD_NAME_FIELD, srp.getAlgorithm()); + credentials = passwordDB.lookup(userID); + } + catch (IOException x) + { + throw new KeyAgreementException("computeSharedSecret()", x); + } + final BigInteger s = new BigInteger( + 1,Util.fromBase64((String) credentials.get(SRPRegistry.SALT_FIELD))); + final BigInteger v = new BigInteger( + 1, Util.fromBase64((String) credentials.get(SRPRegistry.USER_VERIFIER_FIELD))); + final SRPKeyPairGenerator kpg = new SRPKeyPairGenerator(); + final Map attributes = new HashMap(); + if (rnd != null) + attributes.put(SRPKeyPairGenerator.SOURCE_OF_RANDOMNESS, rnd); + attributes.put(SRPKeyPairGenerator.SHARED_MODULUS, N); + attributes.put(SRPKeyPairGenerator.GENERATOR, g); + attributes.put(SRPKeyPairGenerator.USER_VERIFIER, v); + kpg.setup(attributes); + hostKeyPair = kpg.generate(); + final BigInteger B = ((SRPPublicKey) hostKeyPair.getPublic()).getY(); + final BigInteger u = uValue(A, B); // u = H(A | B) + // compute S = (Av^u) ^ b + final BigInteger b = ((SRPPrivateKey) hostKeyPair.getPrivate()).getX(); + final BigInteger S = A.multiply(v.modPow(u, N)).modPow(b, N); + final byte[] sBytes = Util.trim(S); + final IMessageDigest hash = srp.newDigest(); + hash.update(sBytes, 0, sBytes.length); + K = new BigInteger(1, hash.digest()); + final OutgoingMessage result = new OutgoingMessage(); + result.writeMPI(s); + result.writeMPI(B); + complete = true; + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java new file mode 100644 index 000000000..d3d27b381 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java @@ -0,0 +1,141 @@ +/* SRP6KeyAgreement.java -- + Copyright (C) 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.crypto.key.srp6; + +import gnu.java.security.Registry; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.util.Util; + +import gnu.javax.crypto.key.BaseKeyAgreementParty; +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.sasl.srp.SRP; + +import java.math.BigInteger; + +/** + * The Secure Remote Password (SRP) key agreement protocol, also known as SRP-6, + * is designed by Thomas J. Wu (see references). The protocol, and its elements + * are described as follows: + *
+ *  N    A large safe prime (N = 2q+1, where q is prime)
+ *       All arithmetic is done modulo N.
+ *  g    A generator modulo N
+ *  s    User's salt
+ *  I    Username
+ *  p    Cleartext Password
+ *  H()  One-way hash function
+ *  ˆ    (Modular) Exponentiation
+ *  u    Random scrambling parameter
+ *  a,b  Secret ephemeral values
+ *  A,B  Public ephemeral values
+ *  x    Private key (derived from p and s)
+ *  v    Password verifier
+ *
+ *  The host stores passwords using the following formula:
+ *  x = H(s | H(I ":" p))           (s is chosen randomly)
+ *  v = gˆx                         (computes password verifier)
+ *
+ *  The host then keeps {I, s, v} in its password database.
+ *
+ *  The authentication protocol itself goes as follows:
+ *  User -> Host:  I, A = gˆa         (identifies self, a = random number)
+ *  Host -> User:  s, B = 3v + gˆb    (sends salt, b = random number)
+ *
+ *  Both:  u = H(A, B)
+ *
+ *  User:  x = H(s, p)               (user enters password)
+ *  User:  S = (B - 3gˆx) ˆ (a + ux) (computes session key)
+ *  User:  K = H(S)
+ *
+ *  Host:  S = (Avˆu) ˆ b            (computes session key)
+ *  Host:  K = H(S)
+ * 
+ *

+ * Reference: + *

    + *
  1. SRP Protocol Design
    + * Thomas J. Wu.
  2. + *
+ */ +public abstract class SRP6KeyAgreement + extends BaseKeyAgreementParty +{ + public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.srp6.ka.prng"; + public static final String SHARED_MODULUS = "gnu.crypto.srp6.ka.N"; + public static final String GENERATOR = "gnu.crypto.srp6.ka.g"; + public static final String HASH_FUNCTION = "gnu.crypto.srp6.ka.H"; + public static final String USER_IDENTITY = "gnu.crypto.srp6.ka.I"; + public static final String USER_PASSWORD = "gnu.crypto.srp6.ka.p"; + public static final String HOST_PASSWORD_DB = "gnu.crypto.srp6.ka.password.db"; + protected static final BigInteger THREE = BigInteger.valueOf(3L); + protected SRP srp; + protected BigInteger N; + protected BigInteger g; + /** The shared secret key. */ + protected BigInteger K; + + protected SRP6KeyAgreement() + { + super(Registry.SRP6_KA); + } + + protected byte[] engineSharedSecret() throws KeyAgreementException + { + return Util.trim(K); + } + + protected void engineReset() + { + srp = null; + N = null; + g = null; + K = null; + } + + protected BigInteger uValue(final BigInteger A, final BigInteger B) + { + final IMessageDigest hash = srp.newDigest(); + byte[] b; + b = Util.trim(A); + hash.update(b, 0, b.length); + b = Util.trim(B); + hash.update(b, 0, b.length); + return new BigInteger(1, hash.digest()); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslClient.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslClient.java new file mode 100644 index 000000000..ec5cd7f17 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslClient.java @@ -0,0 +1,90 @@ +/* SRP6SaslClient.java -- + Copyright (C) 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.crypto.key.srp6; + +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.util.Util; + +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.OutgoingMessage; + +import java.math.BigInteger; + +/** + * A variation of the SRP-6 protocol as used in the SASL-SRP mechanism, for the + * User (client side). + *

+ * In this alternative, the exchange goes as follows: + * + *

+ *     C -> S:  I                      (identifies self)
+ *     S -> C:  N, g, s, B = 3v + gˆb  (sends salt, b = random number)
+ *     C -> S:  A = gˆa                (a = random number)
+ * 
+ * + *

+ * All elements are computed the same way as in the standard version. + *

+ * Reference: + *

    + *
  1. + * Secure Remote Password Authentication Mechanism
    + * K. Burdis, R. Naffah.
  2. + *
  3. SRP Protocol Design
    + * Thomas J. Wu.
  4. + *
+ */ +public class SRP6SaslClient + extends SRP6TLSClient +{ + // default 0-arguments constructor + + protected OutgoingMessage computeSharedSecret(final IncomingMessage in) + throws KeyAgreementException + { + final OutgoingMessage result = super.computeSharedSecret(in); + final byte[] sBytes = Util.trim(K); + final IMessageDigest hash = srp.newDigest(); + hash.update(sBytes, 0, sBytes.length); + K = new BigInteger(1, hash.digest()); + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslServer.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslServer.java new file mode 100644 index 000000000..a4313f4d3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslServer.java @@ -0,0 +1,90 @@ +/* SRP6SaslServer.java -- + Copyright (C) 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.crypto.key.srp6; + +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.util.Util; + +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.OutgoingMessage; + +import java.math.BigInteger; + +/** + * A variation of the SRP-6 protocol as used in the SASL-SRP mechanism, for the + * Host (server side). + *

+ * In this alternative, the exchange goes as follows: + * + *

+ *     C -> S:  I                      (identifies self)
+ *     S -> C:  N, g, s, B = 3v + gˆb  (sends salt, b = random number)
+ *     C -> S:  A = gˆa                (a = random number)
+ * 
+ * + *

+ * All elements are computed the same way as in the standard version. + *

+ * Reference: + *

    + *
  1. + * Secure Remote Password Authentication Mechanism
    + * K. Burdis, R. Naffah.
  2. + *
  3. SRP Protocol Design
    + * Thomas J. Wu.
  4. + *
+ */ +public class SRP6SaslServer + extends SRP6TLSServer +{ + // default 0-arguments constructor + + protected OutgoingMessage computeSharedSecret(final IncomingMessage in) + throws KeyAgreementException + { + super.computeSharedSecret(in); + final byte[] sBytes = Util.trim(K); + final IMessageDigest hash = srp.newDigest(); + hash.update(sBytes, 0, sBytes.length); + K = new BigInteger(1, hash.digest()); + return null; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSClient.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSClient.java new file mode 100644 index 000000000..c2459f620 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSClient.java @@ -0,0 +1,155 @@ +/* SRP6TLSClient.java -- + Copyright (C) 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.crypto.key.srp6; + +import gnu.java.security.util.Util; +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.OutgoingMessage; +import gnu.javax.crypto.sasl.srp.SRP; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.SecureRandom; +import java.util.HashMap; +import java.util.Map; + +/** + * A variation of the SRP6 key agreement protocol, for the client-side as + * proposed in Using + * SRP for TLS Authentication. The only difference between it and the SASL + * variant is that the shared secret is the entity S and not + * H(S). + */ +public class SRP6TLSClient + extends SRP6KeyAgreement +{ + /** The user's identity. */ + private String I; + /** The user's cleartext password. */ + private byte[] p; + /** The user's ephemeral key pair. */ + private KeyPair userKeyPair; + + // default 0-arguments constructor + + protected void engineInit(final Map attributes) throws KeyAgreementException + { + rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS); + final String md = (String) attributes.get(HASH_FUNCTION); + if (md == null || md.trim().length() == 0) + throw new KeyAgreementException("missing hash function"); + srp = SRP.instance(md); + I = (String) attributes.get(USER_IDENTITY); + if (I == null) + throw new KeyAgreementException("missing user identity"); + p = (byte[]) attributes.get(USER_PASSWORD); + if (p == null) + throw new KeyAgreementException("missing user password"); + } + + protected OutgoingMessage engineProcessMessage(final IncomingMessage in) + throws KeyAgreementException + { + switch (step) + { + case 0: + return sendIdentity(in); + case 1: + return computeSharedSecret(in); + default: + throw new IllegalStateException("unexpected state"); + } + } + + protected void engineReset() + { + I = null; + p = null; + userKeyPair = null; + super.engineReset(); + } + + private OutgoingMessage sendIdentity(final IncomingMessage in) + throws KeyAgreementException + { + final OutgoingMessage result = new OutgoingMessage(); + result.writeString(I); + return result; + } + + protected OutgoingMessage computeSharedSecret(final IncomingMessage in) + throws KeyAgreementException + { + N = in.readMPI(); + g = in.readMPI(); + final BigInteger s = in.readMPI(); + final BigInteger B = in.readMPI(); + // generate an ephemeral keypair + final SRPKeyPairGenerator kpg = new SRPKeyPairGenerator(); + final Map attributes = new HashMap(); + if (rnd != null) + attributes.put(SRPKeyPairGenerator.SOURCE_OF_RANDOMNESS, rnd); + attributes.put(SRPKeyPairGenerator.SHARED_MODULUS, N); + attributes.put(SRPKeyPairGenerator.GENERATOR, g); + kpg.setup(attributes); + userKeyPair = kpg.generate(); + final BigInteger A = ((SRPPublicKey) userKeyPair.getPublic()).getY(); + final BigInteger u = uValue(A, B); // u = H(A | B) + final BigInteger x; + try + { + x = new BigInteger(1, srp.computeX(Util.trim(s), I, p)); + } + catch (Exception e) + { + throw new KeyAgreementException("computeSharedSecret()", e); + } + // compute S = (B - 3g^x) ^ (a + ux) + final BigInteger a = ((SRPPrivateKey) userKeyPair.getPrivate()).getX(); + final BigInteger S = B.subtract(THREE.multiply(g.modPow(x, N))) + .modPow(a.add(u.multiply(x)), N); + K = S; + final OutgoingMessage result = new OutgoingMessage(); + result.writeMPI(A); + complete = true; + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSServer.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSServer.java new file mode 100644 index 000000000..42e3d9cb1 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSServer.java @@ -0,0 +1,177 @@ +/* SRP6TLSServer.java -- + Copyright (C) 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.crypto.key.srp6; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.OutgoingMessage; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.sasl.srp.SRP; +import gnu.javax.crypto.sasl.srp.SRPAuthInfoProvider; +import gnu.javax.crypto.sasl.srp.SRPRegistry; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.SecureRandom; +import java.util.HashMap; +import java.util.Map; + +/** + * A variation of the SRP6 key agreement protocol, for the server-side as + * proposed in Using + * SRP for TLS Authentication. The only difference between it and the SASL + * variant is that the shared secret is the entity S and not + * H(S). + */ +public class SRP6TLSServer + extends SRP6KeyAgreement +{ + /** The user's ephemeral key pair. */ + private KeyPair hostKeyPair; + /** The SRP password database. */ + private SRPAuthInfoProvider passwordDB; + + // default 0-arguments constructor + + protected void engineInit(final Map attributes) throws KeyAgreementException + { + rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS); + final String md = (String) attributes.get(HASH_FUNCTION); + if (md == null || md.trim().length() == 0) + throw new KeyAgreementException("missing hash function"); + srp = SRP.instance(md); + passwordDB = (SRPAuthInfoProvider) attributes.get(HOST_PASSWORD_DB); + if (passwordDB == null) + throw new KeyAgreementException("missing SRP password database"); + } + + protected OutgoingMessage engineProcessMessage(final IncomingMessage in) + throws KeyAgreementException + { + switch (step) + { + case 0: + return sendParameters(in); + case 1: + return computeSharedSecret(in); + default: + throw new IllegalStateException("unexpected state"); + } + } + + protected void engineReset() + { + hostKeyPair = null; + super.engineReset(); + } + + private OutgoingMessage sendParameters(final IncomingMessage in) + throws KeyAgreementException + { + final String I = in.readString(); + // get s and v for user identified by I + // ---------------------------------------------------------------------- + final Map credentials; + try + { + final Map userID = new HashMap(); + userID.put(Registry.SASL_USERNAME, I); + userID.put(SRPRegistry.MD_NAME_FIELD, srp.getAlgorithm()); + credentials = passwordDB.lookup(userID); + } + catch (IOException x) + { + throw new KeyAgreementException("computeSharedSecret()", x); + } + + final BigInteger s = new BigInteger( + 1, Util.fromBase64((String) credentials.get(SRPRegistry.SALT_FIELD))); + final BigInteger v = new BigInteger( + 1, Util.fromBase64((String) credentials.get(SRPRegistry.USER_VERIFIER_FIELD))); + final Map configuration; + try + { + final String mode = (String) credentials.get(SRPRegistry.CONFIG_NDX_FIELD); + configuration = passwordDB.getConfiguration(mode); + } + catch (IOException x) + { + throw new KeyAgreementException("computeSharedSecret()", x); + } + N = new BigInteger( + 1, Util.fromBase64((String) configuration.get(SRPRegistry.SHARED_MODULUS))); + g = new BigInteger( + 1, Util.fromBase64((String) configuration.get(SRPRegistry.FIELD_GENERATOR))); + // generate an ephemeral keypair + final SRPKeyPairGenerator kpg = new SRPKeyPairGenerator(); + final Map attributes = new HashMap(); + if (rnd != null) + attributes.put(SRPKeyPairGenerator.SOURCE_OF_RANDOMNESS, rnd); + attributes.put(SRPKeyPairGenerator.SHARED_MODULUS, N); + attributes.put(SRPKeyPairGenerator.GENERATOR, g); + attributes.put(SRPKeyPairGenerator.USER_VERIFIER, v); + kpg.setup(attributes); + hostKeyPair = kpg.generate(); + final BigInteger B = ((SRPPublicKey) hostKeyPair.getPublic()).getY(); + final OutgoingMessage result = new OutgoingMessage(); + result.writeMPI(N); + result.writeMPI(g); + result.writeMPI(s); + result.writeMPI(B); + return result; + } + + protected OutgoingMessage computeSharedSecret(final IncomingMessage in) + throws KeyAgreementException + { + final BigInteger A = in.readMPI(); + final BigInteger B = ((SRPPublicKey) hostKeyPair.getPublic()).getY(); + final BigInteger u = uValue(A, B); // u = H(A | B) + // compute S = (Av^u) ^ b + final BigInteger b = ((SRPPrivateKey) hostKeyPair.getPrivate()).getX(); + final BigInteger v = ((SRPPrivateKey) hostKeyPair.getPrivate()).getV(); + final BigInteger S = A.multiply(v.modPow(u, N)).modPow(b, N); + K = S; + complete = true; + return null; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6User.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6User.java new file mode 100644 index 000000000..4a1e8dda9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6User.java @@ -0,0 +1,163 @@ +/* SRP6User.java -- + Copyright (C) 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.crypto.key.srp6; + +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.util.Util; +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.OutgoingMessage; +import gnu.javax.crypto.sasl.srp.SRP; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.SecureRandom; +import java.util.HashMap; +import java.util.Map; + +/** + * The implementation of the User in the SRP-6 protocol. + *

+ * Reference: + *

    + *
  1. SRP Protocol Design
    + * Thomas J. Wu.
  2. + *
+ */ +public class SRP6User + extends SRP6KeyAgreement +{ + /** The user's identity. */ + private String I; + /** The user's cleartext password. */ + private byte[] p; + /** The user's ephemeral key pair. */ + private KeyPair userKeyPair; + + // default 0-arguments constructor + + protected void engineInit(final Map attributes) throws KeyAgreementException + { + rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS); + N = (BigInteger) attributes.get(SHARED_MODULUS); + if (N == null) + throw new KeyAgreementException("missing shared modulus"); + g = (BigInteger) attributes.get(GENERATOR); + if (g == null) + throw new KeyAgreementException("missing generator"); + final String md = (String) attributes.get(HASH_FUNCTION); + if (md == null || md.trim().length() == 0) + throw new KeyAgreementException("missing hash function"); + srp = SRP.instance(md); + I = (String) attributes.get(USER_IDENTITY); + if (I == null) + throw new KeyAgreementException("missing user identity"); + p = (byte[]) attributes.get(USER_PASSWORD); + if (p == null) + throw new KeyAgreementException("missing user password"); + } + + protected OutgoingMessage engineProcessMessage(final IncomingMessage in) + throws KeyAgreementException + { + switch (step) + { + case 0: + return sendIdentity(in); + case 1: + return computeSharedSecret(in); + default: + throw new IllegalStateException("unexpected state"); + } + } + + protected void engineReset() + { + I = null; + p = null; + userKeyPair = null; + super.engineReset(); + } + + private OutgoingMessage sendIdentity(final IncomingMessage in) + throws KeyAgreementException + { + // generate an ephemeral keypair + final SRPKeyPairGenerator kpg = new SRPKeyPairGenerator(); + final Map attributes = new HashMap(); + if (rnd != null) + attributes.put(SRPKeyPairGenerator.SOURCE_OF_RANDOMNESS, rnd); + attributes.put(SRPKeyPairGenerator.SHARED_MODULUS, N); + attributes.put(SRPKeyPairGenerator.GENERATOR, g); + kpg.setup(attributes); + userKeyPair = kpg.generate(); + final OutgoingMessage result = new OutgoingMessage(); + result.writeString(I); + result.writeMPI(((SRPPublicKey) userKeyPair.getPublic()).getY()); + return result; + } + + private OutgoingMessage computeSharedSecret(final IncomingMessage in) + throws KeyAgreementException + { + final BigInteger s = in.readMPI(); + final BigInteger B = in.readMPI(); + final BigInteger A = ((SRPPublicKey) userKeyPair.getPublic()).getY(); + final BigInteger u = uValue(A, B); // u = H(A | B) + final BigInteger x; + try + { + x = new BigInteger(1, srp.computeX(Util.trim(s), I, p)); + } + catch (Exception e) + { + throw new KeyAgreementException("computeSharedSecret()", e); + } + // compute S = (B - 3g^x) ^ (a + ux) + final BigInteger a = ((SRPPrivateKey) userKeyPair.getPrivate()).getX(); + final BigInteger S = B.subtract(THREE.multiply(g.modPow(x, N))) + .modPow(a.add(u.multiply(x)), N); + final byte[] sBytes = Util.trim(S); + final IMessageDigest hash = srp.newDigest(); + hash.update(sBytes, 0, sBytes.length); + K = new BigInteger(1, hash.digest()); + complete = true; + return null; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRPAlgorithm.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPAlgorithm.java new file mode 100644 index 000000000..fb8249e05 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPAlgorithm.java @@ -0,0 +1,131 @@ +/* SRPAlgorithm.java -- + Copyright (C) 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.crypto.key.srp6; + +import gnu.javax.crypto.sasl.srp.SRPRegistry; + +import java.math.BigInteger; + +/** + * Utilities for use with SRP-6 based methods and protocols. + *

+ * Reference: + *

    + *
  1. SRP Protocol Design
    + * Thomas J. Wu.
  2. + *
+ */ +public class SRPAlgorithm +{ + // lifted from draft-burdis-cat-srp-sasl-09 + public static final BigInteger N_2048 = new BigInteger( + "AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050" + + "A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50" + + "E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B8" + + "55F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773B" + + "CA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748" + + "544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6" + + "AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB6" + + "94B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73", 16); + public static final BigInteger N_1536 = new BigInteger( + "9DEF3CAFB939277AB1F12A8617A47BBBDBA51DF499AC4C80BEEEA9614B19CC4D" + + "5F4F5F556E27CBDE51C6A94BE4607A291558903BA0D0F84380B655BB9A22E8DC" + + "DF028A7CEC67F0D08134B1C8B97989149B609E0BE3BAB63D47548381DBC5B1FC" + + "764E3F4B53DD9DA1158BFD3E2B9C8CF56EDF019539349627DB2FD53D24B7C486" + + "65772E437D6C7F8CE442734AF7CCB7AE837C264AE3A9BEB87F8A2FE9B8B5292E" + + "5A021FFF5E91479E8CE7A28C2442C6F315180F93499A234DCF76E3FED135F9BB", 16); + public static final BigInteger N_1280 = new BigInteger( + "D77946826E811914B39401D56A0A7843A8E7575D738C672A090AB1187D690DC4" + + "3872FC06A7B6A43F3B95BEAEC7DF04B9D242EBDC481111283216CE816E004B78" + + "6C5FCE856780D41837D95AD787A50BBE90BD3A9C98AC0F5FC0DE744B1CDE1891" + + "690894BC1F65E00DE15B4B2AA6D87100C9ECC2527E45EB849DEB14BB2049B163" + + "EA04187FD27C1BD9C7958CD40CE7067A9C024F9B7C5A0B4F5003686161F0605B", 16); + public static final BigInteger N_1024 = new BigInteger( + "EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C9C256576" + + "D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE48E495C1D6089DAD1" + + "5DC7D7B46154D6B6CE8EF4AD69B15D4982559B297BCF1885C529F566660E57EC" + + "68EDBC3C05726CC02FD4CBF4976EAA9AFD5138FE8376435B9FC61D2FC0EB06E3", 16); + public static final BigInteger N_768 = new BigInteger( + "B344C7C4F8C495031BB4E04FF8F84EE95008163940B9558276744D91F7CC9F40" + + "2653BE7147F00F576B93754BCDDF71B636F2099E6FFF90E79575F3D0DE694AFF" + + "737D9BE9713CEF8D837ADA6380B1093E94B6A529A8C6C2BE33E0867C60C3262B", 16); + public static final BigInteger N_640 = new BigInteger( + "C94D67EB5B1A2346E8AB422FC6A0EDAEDA8C7F894C9EEEC42F9ED250FD7F0046" + + "E5AF2CF73D6B2FA26BB08033DA4DE322E144E7A8E9B12A0E4637F6371F34A207" + + "1C4B3836CBEEAB15034460FAA7ADF483", 16); + public static final BigInteger N_512 = new BigInteger( + "D4C7F8A2B32C11B8FBA9581EC4BA4F1B04215642EF7355E37C0FC0443EF756EA" + + "2C6B8EEB755A1C723027663CAA265EF785B8FF6A9B35227A52D86633DBDFCA43", 16); + public static final BigInteger N_384 = new BigInteger( + "8025363296FB943FCE54BE717E0E2958A02A9672EF561953B2BAA3BAACC3ED57" + + "54EB764C7AB7184578C57D5949CCB41B", 16); + public static final BigInteger N_264 = new BigInteger( + "115B8B692E0E045692CF280B436735C77A5A9E8A9E7ED56C965F87DB5B2A2ECE3", 16); + private static final BigInteger ZERO = BigInteger.ZERO; + private static final BigInteger ONE = BigInteger.ONE; + private static final BigInteger TWO = BigInteger.valueOf(2L); + + /** Trivial constructor to enforce usage through class methods. */ + private SRPAlgorithm() + { + super(); + } + + public static void checkParams(final BigInteger N, final BigInteger g) + { + // 1. N should be at least 512-bit long + final int blen = N.bitLength(); + if (blen < SRPRegistry.MINIMUM_MODULUS_BITLENGTH) + throw new IllegalArgumentException("Bit length of N (" + + blen + + ") is too low. Should be at least " + + SRPRegistry.MINIMUM_MODULUS_BITLENGTH); + // 2. N should be a prime + if (! N.isProbablePrime(80)) + throw new IllegalArgumentException("N should be prime but isn't"); + // 3. N should be of the form 2*q + 1, where q is prime + final BigInteger q = N.subtract(ONE).divide(TWO); + if (! q.isProbablePrime(80)) + throw new IllegalArgumentException("(N-1)/2 should be prime but isn't"); + // 4. g**q should be -1 mod N + final BigInteger gq = g.modPow(q, N).add(ONE).mod(N); + if (gq.compareTo(ZERO) != 0) + throw new IllegalArgumentException("g**q should be -1 (mod N) but isn't"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKey.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKey.java new file mode 100644 index 000000000..72ce8d2cf --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKey.java @@ -0,0 +1,147 @@ +/* SRPKey.java -- + Copyright (C) 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.crypto.key.srp6; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.io.Serializable; +import java.math.BigInteger; +import java.security.Key; + +/** + * An abstract representation of a base SRP ephemeral key. + *

+ * This object encapsulates the two numbers: + *

+ *

+ * Note that in SRP, all arithmetic is done modulo N. + *

+ * Reference: + *

    + *
  1. SRP Protocol Design
    + * Thomas J. Wu.
  2. + *
+ */ +public abstract class SRPKey + implements Key, Serializable +{ + /** The public, Germaine prime, shared modulus. */ + protected final BigInteger N; + /** The generator. */ + protected final BigInteger g; + + protected SRPKey(BigInteger N, BigInteger g) + { + super(); + + this.N = N; + this.g = g; + } + + /** + * Returns the standard algorithm name for this key. + * + * @return the standard algorithm name for this key. + */ + public String getAlgorithm() + { + return Registry.SRP_KPG; + } + + /** @deprecated see getEncoded(int). */ + public byte[] getEncoded() + { + return getEncoded(IKeyPairCodec.RAW_FORMAT); + } + + /** + * Returns {@link Registry#RAW_ENCODING_SHORT_NAME} which is the sole format + * supported for this type of keys. + * + * @return {@link Registry#RAW_ENCODING_SHORT_NAME} ALWAYS. + */ + public String getFormat() + { + return Registry.RAW_ENCODING_SHORT_NAME; + } + + /** + * Returns the public shared modulus. + * + * @return N. + */ + public BigInteger getN() + { + return N; + } + + /** + * Returns the generator. + * + * @return g. + */ + public BigInteger getG() + { + return g; + } + + /** + * Returns true if the designated object is an instance of + * SRPKey and has the same SRP parameter values as this one. + * + * @param obj the other non-null SRP key to compare to. + * @return true if the designated object is of the same type + * and value as this one. + */ + public boolean equals(Object obj) + { + if (obj == null) + return false; + if (! (obj instanceof SRPKey)) + return false; + SRPKey that = (SRPKey) obj; + return N.equals(that.getN()) && g.equals(that.getG()); + } + + public abstract byte[] getEncoded(int format); +} diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java new file mode 100644 index 000000000..59e5bc943 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java @@ -0,0 +1,282 @@ +/* SRPKeyPairGenerator.java -- + Copyright (C) 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.crypto.key.srp6; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairGenerator; +import gnu.java.security.util.PRNG; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.SecureRandom; +import java.util.Map; +import java.util.logging.Logger; + +/** + * Reference: + *
    + *
  1. SRP Protocol Design
    + * Thomas J. Wu.
  2. + *
+ */ +public class SRPKeyPairGenerator + implements IKeyPairGenerator +{ + private static final Logger log = Logger.getLogger(SRPKeyPairGenerator.class.getName()); + private static final BigInteger ZERO = BigInteger.ZERO; + private static final BigInteger ONE = BigInteger.ONE; + private static final BigInteger TWO = BigInteger.valueOf(2L); + private static final BigInteger THREE = BigInteger.valueOf(3L); + /** Property name of the length (Integer) of the modulus (N) of an SRP key. */ + public static final String MODULUS_LENGTH = "gnu.crypto.srp.L"; + /** Property name of the Boolean indicating wether or not to use defaults. */ + public static final String USE_DEFAULTS = "gnu.crypto.srp.use.defaults"; + /** Property name of the modulus (N) of an SRP key. */ + public static final String SHARED_MODULUS = "gnu.crypto.srp.N"; + /** Property name of the generator (g) of an SRP key. */ + public static final String GENERATOR = "gnu.crypto.srp.g"; + /** Property name of the user's verifier (v) for a Server SRP key. */ + public static final String USER_VERIFIER = "gnu.crypto.srp.v"; + /** + * Property name of an optional {@link SecureRandom} instance to use. The + * default is to use a classloader singleton from {@link PRNG}. + */ + public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.srp.prng"; + /** Default value for the modulus length. */ + private static final int DEFAULT_MODULUS_LENGTH = 1024; + /** The optional {@link SecureRandom} instance to use. */ + private SecureRandom rnd = null; + /** Bit length of the shared modulus. */ + private int l; + /** The shared public modulus. */ + private BigInteger N; + /** The Field generator. */ + private BigInteger g; + /** The user's verifier MPI. */ + private BigInteger v; + /** Our default source of randomness. */ + private PRNG prng = null; + + // implicit 0-arguments constructor + + public String name() + { + return Registry.SRP_KPG; + } + + public void setup(Map attributes) + { + // do we have a SecureRandom, or should we use our own? + rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS); + N = (BigInteger) attributes.get(SHARED_MODULUS); + if (N != null) + { + l = N.bitLength(); + g = (BigInteger) attributes.get(GENERATOR); + if (g == null) + g = TWO; + SRPAlgorithm.checkParams(N, g); + } + else + { // generate or use default values for N and g + Boolean useDefaults = (Boolean) attributes.get(USE_DEFAULTS); + if (useDefaults == null) + useDefaults = Boolean.TRUE; + Integer L = (Integer) attributes.get(MODULUS_LENGTH); + l = DEFAULT_MODULUS_LENGTH; + if (useDefaults.equals(Boolean.TRUE)) + { + if (L != null) + { + l = L.intValue(); + switch (l) + { + case 512: + N = SRPAlgorithm.N_512; + break; + case 640: + N = SRPAlgorithm.N_640; + break; + case 768: + N = SRPAlgorithm.N_768; + break; + case 1024: + N = SRPAlgorithm.N_1024; + break; + case 1280: + N = SRPAlgorithm.N_1280; + break; + case 1536: + N = SRPAlgorithm.N_1536; + break; + case 2048: + N = SRPAlgorithm.N_2048; + break; + default: + throw new IllegalArgumentException( + "unknown default shared modulus bit length"); + } + g = TWO; + l = N.bitLength(); + } + } + else // generate new N and g + { + if (L != null) + { + l = L.intValue(); + if ((l % 256) != 0 || l < 512 || l > 2048) + throw new IllegalArgumentException( + "invalid shared modulus bit length"); + } + } + } + // are we using this generator on the server side, or the client side? + v = (BigInteger) attributes.get(USER_VERIFIER); + } + + public KeyPair generate() + { + if (N == null) + { + BigInteger[] params = generateParameters(); + BigInteger q = params[0]; + N = params[1]; + g = params[2]; + if (Configuration.DEBUG) + { + log.fine("q: " + q.toString(16)); + log.fine("N: " + N.toString(16)); + log.fine("g: " + g.toString(16)); + } + } + return (v != null ? hostKeyPair() : userKeyPair()); + } + + private synchronized BigInteger[] generateParameters() + { + // N A large safe prime (N = 2q+1, where q is prime) + // g A generator modulo N + BigInteger q, p, g; + byte[] qBytes = new byte[l / 8]; + do + { + do + { + nextRandomBytes(qBytes); + q = new BigInteger(1, qBytes); + q = q.setBit(0).setBit(l - 2).clearBit(l - 1); + } + while (! q.isProbablePrime(80)); + p = q.multiply(TWO).add(ONE); + } + while (p.bitLength() != l || ! p.isProbablePrime(80)); + // compute g. from FIPS-186, Appendix 4: e == 2 + BigInteger p_minus_1 = p.subtract(ONE); + g = TWO; + // Set h = any integer, where 1 < h < p - 1 and + // h differs from any value previously tried + for (BigInteger h = TWO; h.compareTo(p_minus_1) < 0; h = h.add(ONE)) + { + // Set g = h**2 mod p + g = h.modPow(TWO, p); + // If g = 1, go to step 3 + if (! g.equals(ONE)) + break; + } + return new BigInteger[] { q, p, g }; + } + + private KeyPair hostKeyPair() + { + byte[] bBytes = new byte[(l + 7) / 8]; + BigInteger b, B; + do + { + do + { + nextRandomBytes(bBytes); + b = new BigInteger(1, bBytes); + } + while (b.compareTo(ONE) <= 0 || b.compareTo(N) >= 0); + B = THREE.multiply(v).add(g.modPow(b, N)).mod(N); + } + while (B.compareTo(ZERO) == 0 || B.compareTo(N) >= 0); + KeyPair result = new KeyPair(new SRPPublicKey(new BigInteger[] { N, g, B }), + new SRPPrivateKey(new BigInteger[] { N, g, b, v })); + return result; + } + + private KeyPair userKeyPair() + { + byte[] aBytes = new byte[(l + 7) / 8]; + BigInteger a, A; + do + { + do + { + nextRandomBytes(aBytes); + a = new BigInteger(1, aBytes); + } + while (a.compareTo(ONE) <= 0 || a.compareTo(N) >= 0); + A = g.modPow(a, N); + } + while (A.compareTo(ZERO) == 0 || A.compareTo(N) >= 0); + KeyPair result = new KeyPair(new SRPPublicKey(new BigInteger[] { N, g, A }), + new SRPPrivateKey(new BigInteger[] { N, g, a })); + return result; + } + + private void nextRandomBytes(byte[] buffer) + { + if (rnd != null) + rnd.nextBytes(buffer); + else + getDefaultPRNG().nextBytes(buffer); + } + + private PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + + return prng; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java new file mode 100644 index 000000000..b7cc53693 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java @@ -0,0 +1,334 @@ +/* SRPKeyPairRawCodec.java -- + Copyright (C) 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.crypto.key.srp6; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.io.ByteArrayOutputStream; +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; + +/** + * An object that implements the {@link IKeyPairCodec} operations for the + * Raw format to use with SRP keypairs. + *

+ * Reference: + *

    + *
  1. SRP Protocol Design
    + * Thomas J. Wu.
  2. + *
+ */ +public class SRPKeyPairRawCodec + implements IKeyPairCodec +{ + // implicit 0-arguments constructor + + public int getFormatID() + { + return RAW_FORMAT; + } + + /** + * Returns the encoded form of the designated SRP public key according to the + * Raw format supported by this library. + *

+ * The Raw format for an SRP public key, in this implementation, is a + * byte sequence consisting of the following: + *

    + *
  1. 4-byte magic consisting of the value of the literal + * {@link Registry#MAGIC_RAW_SRP_PUBLIC_KEY},
  2. + *
  3. 1-byte version consisting of the constant: 0x01,
  4. + *
  5. 4-byte count of following bytes representing the SRP parameter + * N in internet order,
  6. + *
  7. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the SRP parameter N, + *
  8. + *
  9. 4-byte count of following bytes representing the SRP parameter + * g,
  10. + *
  11. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the SRP parameter g, + *
  12. + *
  13. 4-byte count of following bytes representing the SRP parameter + * y,
  14. + *
  15. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the SRP parameter y, + *
  16. + *
+ * + * @param key the key to encode. + * @return the Raw format encoding of the designated key. + * @throws IllegalArgumentException if the designated key is not an SRP one. + */ + public byte[] encodePublicKey(PublicKey key) + { + if (! (key instanceof SRPPublicKey)) + throw new IllegalArgumentException("key"); + SRPPublicKey srpKey = (SRPPublicKey) key; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + // magic + baos.write(Registry.MAGIC_RAW_SRP_PUBLIC_KEY[0]); + baos.write(Registry.MAGIC_RAW_SRP_PUBLIC_KEY[1]); + baos.write(Registry.MAGIC_RAW_SRP_PUBLIC_KEY[2]); + baos.write(Registry.MAGIC_RAW_SRP_PUBLIC_KEY[3]); + // version + baos.write(0x01); + // N + byte[] buffer = srpKey.getN().toByteArray(); + int length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + // g + buffer = srpKey.getG().toByteArray(); + length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + // y + buffer = srpKey.getY().toByteArray(); + length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + return baos.toByteArray(); + } + + public PublicKey decodePublicKey(byte[] k) + { + // magic + if (k[0] != Registry.MAGIC_RAW_SRP_PUBLIC_KEY[0] + || k[1] != Registry.MAGIC_RAW_SRP_PUBLIC_KEY[1] + || k[2] != Registry.MAGIC_RAW_SRP_PUBLIC_KEY[2] + || k[3] != Registry.MAGIC_RAW_SRP_PUBLIC_KEY[3]) + throw new IllegalArgumentException("magic"); + // version + if (k[4] != 0x01) + throw new IllegalArgumentException("version"); + int i = 5; + int l; + byte[] buffer; + // N + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger N = new BigInteger(1, buffer); + // g + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger g = new BigInteger(1, buffer); + // y + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger y = new BigInteger(1, buffer); + return new SRPPublicKey(N, g, y); + } + + /** + * Returns the encoded form of the designated SRP private key according to the + * Raw format supported by this library. + *

+ * The Raw format for an SRP private key, in this implementation, is a + * byte sequence consisting of the following: + *

    + *
  1. 4-byte magic consisting of the value of the literal + * {@link Registry#MAGIC_RAW_SRP_PRIVATE_KEY},
  2. + *
  3. 1-byte version consisting of the constant: 0x01,
  4. + *
  5. 4-byte count of following bytes representing the SRP parameter + * N in internet order,
  6. + *
  7. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the SRP parameter N, + *
  8. + *
  9. 4-byte count of following bytes representing the SRP parameter + * g,
  10. + *
  11. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the SRP parameter g, + *
  12. + *
  13. 4-byte count of following bytes representing the SRP parameter + * x,
  14. + *
  15. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the SRP parameter x, + *
  16. + *
  17. one byte which indicates whether the SRP parameter v is + * included in this encoding (value 0x01) or not (value + * 0x00).
  18. + *
  19. 4-byte count of following bytes representing the SRP parameter + * v,
  20. + *
  21. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the SRP parameter v, + *
  22. + *
+ * + * @param key the key to encode. + * @return the Raw format encoding of the designated key. + * @throws IllegalArgumentException if the designated key is not an SRP one. + */ + public byte[] encodePrivateKey(PrivateKey key) + { + if (! (key instanceof SRPPrivateKey)) + throw new IllegalArgumentException("key"); + SRPPrivateKey srpKey = (SRPPrivateKey) key; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + // magic + baos.write(Registry.MAGIC_RAW_SRP_PRIVATE_KEY[0]); + baos.write(Registry.MAGIC_RAW_SRP_PRIVATE_KEY[1]); + baos.write(Registry.MAGIC_RAW_SRP_PRIVATE_KEY[2]); + baos.write(Registry.MAGIC_RAW_SRP_PRIVATE_KEY[3]); + // version + baos.write(0x01); + // N + byte[] buffer = srpKey.getN().toByteArray(); + int length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + // g + buffer = srpKey.getG().toByteArray(); + length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + // x + buffer = srpKey.getX().toByteArray(); + length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + // v + if (srpKey.getV() != null) + { + baos.write(0x01); + buffer = srpKey.getV().toByteArray(); + length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + } + else + baos.write(0x00); + return baos.toByteArray(); + } + + public PrivateKey decodePrivateKey(byte[] k) + { + // magic + if (k[0] != Registry.MAGIC_RAW_SRP_PRIVATE_KEY[0] + || k[1] != Registry.MAGIC_RAW_SRP_PRIVATE_KEY[1] + || k[2] != Registry.MAGIC_RAW_SRP_PRIVATE_KEY[2] + || k[3] != Registry.MAGIC_RAW_SRP_PRIVATE_KEY[3]) + throw new IllegalArgumentException("magic"); + // version + if (k[4] != 0x01) + throw new IllegalArgumentException("version"); + int i = 5; + int l; + byte[] buffer; + // N + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger N = new BigInteger(1, buffer); + // g + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger g = new BigInteger(1, buffer); + // x + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger x = new BigInteger(1, buffer); + // v + l = k[i++]; + if (l == 0x01) + { + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger v = new BigInteger(1, buffer); + return new SRPPrivateKey(N, g, x, v); + } + return new SRPPrivateKey(N, g, x); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRPPrivateKey.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPPrivateKey.java new file mode 100644 index 000000000..c2e13be82 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPPrivateKey.java @@ -0,0 +1,227 @@ +/* SRPPrivateKey.java -- + Copyright (C) 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.crypto.key.srp6; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.PrivateKey; + +/** + * A representation of an SRP ephemeral private key. + *

+ * Reference: + *

    + *
  1. SRP Protocol Design
    + * Thomas J. Wu.
  2. + *
+ */ +public class SRPPrivateKey + extends SRPKey + implements PrivateKey +{ + /** + * The private exponent for either the server or the client engaged in the SRP + * protocol exchange. + */ + private final BigInteger X; + /** + * The user's verifier (v) --for the server-- also computed at the client side + * as g.modPow(x, N), where x is the hashed output of the user name and + * password . + */ + private final BigInteger v; + + /** + * Public constructor for use from outside this package. + * + * @param N the public shared modulus. + * @param g the generator. + * @param x the private exponent of the ephemeral key. + */ + public SRPPrivateKey(BigInteger N, BigInteger g, BigInteger x) + { + this(N, g, x, null); + } + + /** + * Public constructor for use from outside this package. + * + * @param N the public shared modulus. + * @param g the generator. + * @param x the private exponent of the ephemeral key. + * @param v the user's verifier value (for the server side only). + */ + public SRPPrivateKey(BigInteger N, BigInteger g, BigInteger x, BigInteger v) + { + super(N, g); + + SRPAlgorithm.checkParams(N, g); + this.X = x; + this.v = v; + } + + /** + * Default constructor. Assumes N and g are already validated. + * + * @param params an array of either 3 or 4 values representing N, g, and + * either v and X for the server, or just X for the client. Those + * values represent the following: + *
    + *
  1. v (server side): the user's verifier.
  2. + *
  3. X (both sides): the server's or client's ephemeral private + * exponent.
  4. + *
+ */ + SRPPrivateKey(BigInteger[] params) + { + super(params[0], params[1]); + + if (params.length == 3) + { + X = params[2]; + v = null; + } + else if (params.length == 4) + { + X = params[2]; + v = params[3]; + } + else + throw new IllegalArgumentException("invalid number of SRP parameters"); + } + + /** + * A class method that takes the output of the encodePrivateKey() + * method of an SRP keypair codec object (an instance implementing + * {@link IKeyPairCodec} for DSS keys, and re-constructs an instance of this + * object. + * + * @param k the contents of a previously encoded instance of this object. + * @throws ArrayIndexOutOfBoundsException if there is not enough bytes, in + * k, to represent a valid encoding of an instance + * of this object. + * @throws IllegalArgumentException if the byte sequence does not represent a + * valid encoding of an instance of this object. + */ + public static SRPPrivateKey valueOf(byte[] k) + { + // check magic... + // we should parse here enough bytes to know which codec to use, and + // direct the byte array to the appropriate codec. since we only have one + // codec, we could have immediately tried it; nevertheless since testing + // one byte is cheaper than instatiating a codec that will fail we test + // the first byte before we carry on. + if (k[0] == Registry.MAGIC_RAW_SRP_PRIVATE_KEY[0]) + { + // it's likely to be in raw format. get a raw codec and hand it over + IKeyPairCodec codec = new SRPKeyPairRawCodec(); + return (SRPPrivateKey) codec.decodePrivateKey(k); + } + throw new IllegalArgumentException("magic"); + } + + /** + * Returns the private exponent of the key as a {@link BigInteger}. + * + * @return the private exponent of the key as a {@link BigInteger}. + */ + public BigInteger getX() + { + return X; + } + + /** + * Returns the user's verifier as a {@link BigInteger}. + * + * @return the user's verifier as a {@link BigInteger} if this is an SRP + * private key of a Host, or null if this is a private + * SRP key for a User. + */ + public BigInteger getV() + { + return v; + } + + /** + * Returns the encoded form of this private key according to the designated + * format. + * + * @param format the desired format identifier of the resulting encoding. + * @return the byte sequence encoding this key according to the designated + * format. + * @throws IllegalArgumentException if the format is not supported. + */ + public byte[] getEncoded(int format) + { + byte[] result; + switch (format) + { + case IKeyPairCodec.RAW_FORMAT: + result = new SRPKeyPairRawCodec().encodePrivateKey(this); + break; + default: + throw new IllegalArgumentException("format"); + } + return result; + } + + /** + * Returns true if the designated object is an instance of + * SRPPrivateKey and has the same SRP parameter values as this + * one. + * + * @param obj the other non-null SRP key to compare to. + * @return true if the designated object is of the same type + * and value as this one. + */ + public boolean equals(Object obj) + { + if (obj == null) + return false; + if (! (obj instanceof SRPPrivateKey)) + return false; + SRPPrivateKey that = (SRPPrivateKey) obj; + boolean result = super.equals(that) && X.equals(that.getX()); + if (v != null) + result = result && v.equals(that.getV()); + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRPPublicKey.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPPublicKey.java new file mode 100644 index 000000000..2db13ff4c --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPPublicKey.java @@ -0,0 +1,175 @@ +/* SRPPublicKey.java -- + Copyright (C) 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.crypto.key.srp6; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.PublicKey; + +/** + * A representation of an SRP ephemeral public key. + *

+ * Reference: + *

    + *
  1. SRP Protocol Design
    + * Thomas J. Wu.
  2. + *
+ */ +public class SRPPublicKey + extends SRPKey + implements PublicKey +{ + /** + * The public exponent for either the server or the client engaged in the SRP + * protocol exchange. + */ + private final BigInteger Y; + + /** + * Public constructor for use from outside this package. + * + * @param N the public shared modulus. + * @param g the generator. + * @param Y the public exponent of the ephemeral key. + */ + public SRPPublicKey(BigInteger N, BigInteger g, BigInteger Y) + { + super(N, g); + + SRPAlgorithm.checkParams(N, g); + this.Y = Y; + } + + /** + * Default constructor. Assumes that N and g are already validated. + * + * @param params an array of 3 values representing N, g and Y; the latter + * being the client's or server's public exponent. + */ + SRPPublicKey(BigInteger[] params) + { + super(params[0], params[1]); + + this.Y = params[2]; + } + + /** + * A class method that takes the output of the encodePublicKey() + * method of an SRP keypair codec object (an instance implementing + * {@link IKeyPairCodec} for SRP keys, and re-constructs an instance of this + * object. + * + * @param k the contents of a previously encoded instance of this object. + * @throws ArrayIndexOutOfBoundsException if there is not enough bytes, in + * k, to represent a valid encoding of an instance + * of this object. + * @throws IllegalArgumentException if the byte sequence does not represent a + * valid encoding of an instance of this object. + */ + public static SRPPublicKey valueOf(byte[] k) + { + // check magic... + // we should parse here enough bytes to know which codec to use, and + // direct the byte array to the appropriate codec. since we only have one + // codec, we could have immediately tried it; nevertheless since testing + // one byte is cheaper than instatiating a codec that will fail we test + // the first byte before we carry on. + if (k[0] == Registry.MAGIC_RAW_SRP_PUBLIC_KEY[0]) + { + // it's likely to be in raw format. get a raw codec and hand it over + IKeyPairCodec codec = new SRPKeyPairRawCodec(); + return (SRPPublicKey) codec.decodePublicKey(k); + } + throw new IllegalArgumentException("magic"); + } + + /** + * Returns the public exponent of the key as a {@link BigInteger}. + * + * @return the public exponent of the key as a {@link BigInteger}. + */ + public BigInteger getY() + { + return Y; + } + + /** + * Returns the encoded form of this public key according to the designated + * format. + * + * @param format the desired format identifier of the resulting encoding. + * @return the byte sequence encoding this key according to the designated + * format. + * @throws IllegalArgumentException if the format is not supported. + */ + public byte[] getEncoded(int format) + { + byte[] result; + switch (format) + { + case IKeyPairCodec.RAW_FORMAT: + result = new SRPKeyPairRawCodec().encodePublicKey(this); + break; + default: + throw new IllegalArgumentException("format"); + } + return result; + } + + /** + * Returns true if the designated object is an instance of + * SRPPublicKeyand has the same SRP parameter values as this + * one. + * + * @param obj the other non-null SRP key to compare to. + * @return true if the designated object is of the same type + * and value as this one. + */ + public boolean equals(Object obj) + { + if (obj == null) + return false; + if (! (obj instanceof SRPPublicKey)) + return false; + SRPPublicKey that = (SRPPublicKey) obj; + return super.equals(that) && Y.equals(that.getY()); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/AuthenticatedEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/AuthenticatedEntry.java new file mode 100644 index 000000000..91c3bc6e2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/AuthenticatedEntry.java @@ -0,0 +1,176 @@ +/* AuthenticatedEntry.java -- + Copyright (C) 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.crypto.keyring; + +import gnu.java.security.Registry; +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; +import gnu.javax.crypto.mac.MacOutputStream; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.security.InvalidKeyException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; + +public final class AuthenticatedEntry + extends MaskableEnvelopeEntry + implements Registry +{ + public static final int TYPE = 2; + + public AuthenticatedEntry(String mac, int macLen, Properties properties) + { + super(TYPE, properties); + if (macLen <= 0) + throw new IllegalArgumentException("invalid mac length"); + this.properties.put("mac", mac); + this.properties.put("maclen", String.valueOf(macLen)); + setMasked(false); + } + + private AuthenticatedEntry() + { + super(TYPE); + setMasked(true); + } + + public static AuthenticatedEntry decode(DataInputStream in) + throws IOException + { + AuthenticatedEntry entry = new AuthenticatedEntry(); + entry.properties.decode(in); + if (! entry.properties.containsKey("mac")) + throw new MalformedKeyringException("no mac specified"); + if (! entry.properties.containsKey("maclen")) + throw new MalformedKeyringException("no mac length specified"); + return entry; + } + + /** + * Computes the mac over this envelope's data. This method must be + * called before this entry in encoded. + * + * @param key The key to authenticate with. + * @throws IOException If encoding fails. + * @throws InvalidKeyException If the supplied key is bad. + */ + public void authenticate(byte[] key) throws IOException, InvalidKeyException + { + if (isMasked()) + throw new IllegalStateException("entry is masked"); + IMac m = getMac(key); + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + MacOutputStream macout = new MacOutputStream(bout, m); + DataOutputStream out2 = new DataOutputStream(macout); + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry entry = (Entry) it.next(); + entry.encode(out2); + } + bout.write(m.digest()); + payload = bout.toByteArray(); + } + + /** + * Verifies this entry's payload. This method will unmask this entry, thus it + * must be called before accessing its contents. + * + * @param key The key to use to authenticate. + * @throws InvalidKeyException If the given key is improper. + */ + public void verify(byte[] key) throws InvalidKeyException + { + if (! isMasked() || payload == null) + return; + IMac m = getMac(key); + m.update(payload, 0, payload.length - m.macSize()); + byte[] macValue = new byte[m.macSize()]; + System.arraycopy(payload, payload.length - macValue.length, macValue, 0, + macValue.length); + if (! Arrays.equals(macValue, m.digest())) + throw new IllegalArgumentException("MAC verification failed"); + try + { + int len = payload.length - m.macSize(); + ByteArrayInputStream bais = new ByteArrayInputStream(payload, 0, len); + DataInputStream in = new DataInputStream(bais); + decodeEnvelope(in); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("malformed keyring fragment"); + } + setMasked(false); + payload = null; + } + + protected void encodePayload() throws IOException + { + if (payload == null) + throw new IllegalStateException("not authenticated"); + } + + private IMac getMac(byte[] key) throws InvalidKeyException + { + IMac mac = MacFactory.getInstance(properties.get("mac")); + if (mac == null) + throw new IllegalArgumentException("no such mac: " + properties.get("mac")); + int maclen = 0; + if (! properties.containsKey("maclen")) + throw new IllegalArgumentException("no MAC length"); + try + { + maclen = Integer.parseInt(properties.get("maclen")); + } + catch (NumberFormatException nfe) + { + throw new IllegalArgumentException("bad MAC length"); + } + HashMap macAttr = new HashMap(); + macAttr.put(IMac.MAC_KEY_MATERIAL, key); + macAttr.put(IMac.TRUNCATED_SIZE, Integer.valueOf(maclen)); + mac.init(macAttr); + return mac; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/BaseKeyring.java b/libjava/classpath/gnu/javax/crypto/keyring/BaseKeyring.java new file mode 100644 index 000000000..e93ca8fa3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/BaseKeyring.java @@ -0,0 +1,158 @@ +/* BaseKeyring.java -- + Copyright (C) 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.crypto.keyring; + +import gnu.java.security.Registry; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +public abstract class BaseKeyring + implements IKeyring +{ + /** The top-level keyring data. */ + protected PasswordAuthenticatedEntry keyring; + protected CompressedEntry keyring2; + + public BaseKeyring() + { + } + + public void load(Map attributes) throws IOException + { + InputStream in = (InputStream) attributes.get(KEYRING_DATA_IN); + if (in == null) + throw new IllegalArgumentException("no input stream"); + char[] password = (char[]) attributes.get(KEYRING_PASSWORD); + if (password == null) + password = new char[0]; + + if (in.read() != Registry.GKR_MAGIC[0] + || in.read() != Registry.GKR_MAGIC[1] + || in.read() != Registry.GKR_MAGIC[2] + || in.read() != Registry.GKR_MAGIC[3]) + throw new MalformedKeyringException("magic"); + + load(in, password); + List l = keyring.getEntries(); + if (l.size() == 1 && (l.get(0) instanceof CompressedEntry)) + keyring2 = (CompressedEntry) l.get(0); + } + + public void store(Map attributes) throws IOException + { + OutputStream out = (OutputStream) attributes.get(KEYRING_DATA_OUT); + if (out == null) + throw new IllegalArgumentException("no output stream"); + char[] password = (char[]) attributes.get(KEYRING_PASSWORD); + if (password == null) + password = new char[0]; + if (keyring == null) + throw new IllegalStateException("empty keyring"); + + out.write(Registry.GKR_MAGIC); + store(out, password); + } + + public void reset() + { + keyring = null; + } + + public int size() + { + if (keyring == null) + throw new IllegalStateException("keyring not loaded"); + return ((StringTokenizer) aliases()).countTokens(); + } + + public Enumeration aliases() + { + if (keyring == null) + throw new IllegalStateException("keyring not loaded"); + return new StringTokenizer(keyring.getAliasList(), ";"); + } + + public boolean containsAlias(String alias) + { + if (keyring == null) + throw new IllegalStateException("keyring not loaded"); + return keyring.containsAlias(alias); + } + + public List get(String alias) + { + if (keyring == null) + throw new IllegalStateException("keyring not loaded"); + return keyring.get(alias); + } + + public void add(Entry entry) + { + if (keyring == null) + throw new IllegalStateException("keyring not loaded"); + if (keyring2 != null) + keyring2.add(entry); + else + keyring.add(entry); + } + + public void remove(String alias) + { + if (keyring == null) + throw new IllegalStateException("keyring not loaded"); + keyring.remove(alias); + } + + protected String fixAlias(String alias) + { + return alias.replace(';', '_'); + } + + protected abstract void load(InputStream in, char[] password) + throws IOException; + + protected abstract void store(OutputStream out, char[] password) + throws IOException; +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/BinaryDataEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/BinaryDataEntry.java new file mode 100644 index 000000000..8fb1e0f39 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/BinaryDataEntry.java @@ -0,0 +1,111 @@ +/* BinaryDataEntry.java -- + Copyright (C) 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.crypto.keyring; + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.Date; + +/** + * A binary data entry is a primitive entry that simply contains some amount of + * arbitrary binary data and an optional content type. + */ +public class BinaryDataEntry + extends PrimitiveEntry +{ + public static final int TYPE = 9; + + /** + * Creates a new binary data entry. + * + * @param contentType The content type of this entry. This parameter can be + * null if no content type is needed. + * @param data The data. + * @param creationDate The creation date. + * @param properties This entry's properties. + */ + public BinaryDataEntry(String contentType, byte[] data, Date creationDate, + Properties properties) + { + super(TYPE, creationDate, properties); + if (data == null) + throw new IllegalArgumentException("no data"); + payload = (byte[]) data.clone(); + if (contentType != null) + this.properties.put("content-type", contentType); + } + + private BinaryDataEntry() + { + super(TYPE); + } + + public static BinaryDataEntry decode(DataInputStream in) throws IOException + { + BinaryDataEntry entry = new BinaryDataEntry(); + entry.defaultDecode(in); + return entry; + } + + /** + * Returns the content type of this entry, or null if this + * property is not set. + * + * @return The content type. + */ + public String getContentType() + { + return properties.get("content-type"); + } + + /** + * Returns this object's data field. + * + * @return The data. + */ + public byte[] getData() + { + return getPayload(); + } + + protected void encodePayload() + { + // Empty. + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/CertPathEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/CertPathEntry.java new file mode 100644 index 000000000..e798a93ce --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/CertPathEntry.java @@ -0,0 +1,112 @@ +/* CertPathEntry.java -- + Copyright (C) 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.crypto.keyring; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.util.Date; + +/** + * A primitive entry that contains a path of X.509 certificates. + */ +public final class CertPathEntry + extends PrimitiveEntry +{ + public static final int TYPE = 8; + private Certificate[] path; + + public CertPathEntry(Certificate[] path, Date creationDate, + Properties properties) + { + super(TYPE, creationDate, properties); + if (path == null || path.length == 0) + throw new IllegalArgumentException("no certificate path"); + this.path = (Certificate[]) path.clone(); + } + + private CertPathEntry() + { + super(TYPE); + } + + public static CertPathEntry decode(DataInputStream in) throws IOException + { + CertPathEntry entry = new CertPathEntry(); + entry.properties.decode(in); + entry.makeCreationDate(); + int len = in.readInt(); + MeteredInputStream in2 = new MeteredInputStream(in, len); + try + { + CertificateFactory fact = CertificateFactory.getInstance("X.509"); + entry.path = (Certificate[]) fact.generateCertificates(in2).toArray(new Certificate[0]); + } + catch (CertificateException ce) + { + throw new MalformedKeyringException(ce.toString()); + } + return entry; + } + + public Certificate[] getCertPath() + { + return path; + } + + protected void encodePayload() throws IOException + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + byte[] enc = null; + try + { + for (int i = 0; i < path.length; i++) + bout.write(path[i].getEncoded()); + } + catch (CertificateEncodingException cee) + { + throw new IOException(cee.toString()); + } + payload = bout.toByteArray(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/CertificateEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/CertificateEntry.java new file mode 100644 index 000000000..f574a4fe4 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/CertificateEntry.java @@ -0,0 +1,128 @@ +/* CertificateEntry.java -- + Copyright (C) 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.crypto.keyring; + +import java.io.DataInputStream; +import java.io.IOException; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.util.Date; + +/** + * An immutable class representing a trusted certificate entry. + */ +public final class CertificateEntry + extends PrimitiveEntry +{ + public static final int TYPE = 5; + /** The certificate. */ + private Certificate certificate; + + /** + * Creates a new certificate entry. + * + * @param certificate The certificate. + * @param creationDate The creation date. + * @param properties The alias. + * @throws IllegalArgumentException If any argument is null, or if the alias + * is empty. + */ + public CertificateEntry(Certificate certificate, Date creationDate, + Properties properties) + { + super(TYPE, creationDate, properties); + if (certificate == null) + throw new IllegalArgumentException("no certificate"); + this.certificate = certificate; + this.properties.put("type", certificate.getType()); + } + + private CertificateEntry() + { + super(TYPE); + } + + public static CertificateEntry decode(DataInputStream in) throws IOException + { + CertificateEntry entry = new CertificateEntry(); + entry.properties.decode(in); + entry.makeCreationDate(); + String type = entry.properties.get("type"); + if (type == null) + throw new MalformedKeyringException("no certificate type"); + int len = in.readInt(); + MeteredInputStream in2 = new MeteredInputStream(in, len); + try + { + CertificateFactory fact = CertificateFactory.getInstance(type); + entry.certificate = fact.generateCertificate(in2); + } + catch (CertificateException ce) + { + throw new MalformedKeyringException(ce.toString()); + } + if (! in2.limitReached()) + throw new MalformedKeyringException("extra data at end of payload"); + return entry; + } + + /** + * Returns this entry's certificate. + * + * @return The certificate. + */ + public Certificate getCertificate() + { + return certificate; + } + + protected void encodePayload() throws IOException + { + try + { + payload = certificate.getEncoded(); + } + catch (CertificateEncodingException cee) + { + throw new IOException(cee.toString()); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/CompressedEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/CompressedEntry.java new file mode 100644 index 000000000..8949a41e9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/CompressedEntry.java @@ -0,0 +1,93 @@ +/* CompressedEntry.java -- + Copyright (C) 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.crypto.keyring; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Iterator; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.InflaterInputStream; + +public class CompressedEntry + extends EnvelopeEntry +{ + public static final int TYPE = 4; + + public CompressedEntry(Properties properties) + { + super(TYPE, properties); + this.properties.put("algorithm", "DEFLATE"); + } + + private CompressedEntry() + { + this(new Properties()); + } + + public static CompressedEntry decode(DataInputStream in) throws IOException + { + CompressedEntry entry = new CompressedEntry(); + entry.properties.decode(in); + String alg = entry.properties.get("algorithm"); + if (alg == null) + throw new MalformedKeyringException("no compression algorithm"); + if (! alg.equalsIgnoreCase("DEFLATE")) + throw new MalformedKeyringException("unsupported compression algorithm: " + + alg); + int len = in.readInt(); + MeteredInputStream min = new MeteredInputStream(in, len); + InflaterInputStream infin = new InflaterInputStream(min); + DataInputStream in2 = new DataInputStream(infin); + entry.decodeEnvelope(in2); + return entry; + } + + protected void encodePayload() throws IOException + { + ByteArrayOutputStream buf = new ByteArrayOutputStream(1024); + DeflaterOutputStream dout = new DeflaterOutputStream(buf); + DataOutputStream out2 = new DataOutputStream(dout); + for (Iterator it = entries.iterator(); it.hasNext();) + ((Entry) it.next()).encode(out2); + dout.finish(); + payload = buf.toByteArray(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/EncryptedEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/EncryptedEntry.java new file mode 100644 index 000000000..68a6c2c8a --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/EncryptedEntry.java @@ -0,0 +1,191 @@ +/* EncryptedEntry.java -- + Copyright (C) 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.crypto.keyring; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.mode.ModeFactory; +import gnu.javax.crypto.pad.IPad; +import gnu.javax.crypto.pad.PadFactory; +import gnu.javax.crypto.pad.WrongPaddingException; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.security.InvalidKeyException; +import java.util.HashMap; +import java.util.Iterator; + +public class EncryptedEntry extends MaskableEnvelopeEntry implements Registry +{ + public static final int TYPE = 0; + + public EncryptedEntry(String cipher, String mode, Properties properties) + { + super(TYPE, properties); + if (cipher == null || mode == null) + throw new IllegalArgumentException("neither cipher nor mode can be null"); + properties.put("cipher", cipher); + properties.put("mode", mode); + setMasked(false); + } + + private EncryptedEntry() + { + super(TYPE, new Properties()); + setMasked(true); + } + + public static EncryptedEntry decode(DataInputStream in) throws IOException + { + EncryptedEntry entry = new EncryptedEntry(); + entry.defaultDecode(in); + if (! entry.properties.containsKey("cipher")) + throw new MalformedKeyringException("no cipher"); + if (! entry.properties.containsKey("cipher")) + throw new MalformedKeyringException("no cipher"); + return entry; + } + + public void decrypt(byte[] key, byte[] iv) throws IllegalArgumentException, + WrongPaddingException + { + if (! isMasked() || payload == null) + return; + IMode mode = getMode(key, iv, IMode.DECRYPTION); + IPad padding = null; + padding = PadFactory.getInstance("PKCS7"); + padding.init(mode.currentBlockSize()); + byte[] buf = new byte[payload.length]; + int count = 0; + for (int i = 0; i < payload.length; i++) + { + mode.update(payload, count, buf, count); + count += mode.currentBlockSize(); + } + int padlen = padding.unpad(buf, 0, buf.length); + int len = buf.length - padlen; + DataInputStream in = new DataInputStream(new ByteArrayInputStream(buf, 0, len)); + try + { + decodeEnvelope(in); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("decryption failed"); + } + setMasked(false); + payload = null; + } + + public void encrypt(byte[] key, byte[] iv) throws IOException + { + IMode mode = getMode(key, iv, IMode.ENCRYPTION); + IPad pad = PadFactory.getInstance("PKCS7"); + pad.init(mode.currentBlockSize()); + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + DataOutputStream out2 = new DataOutputStream(bout); + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry entry = (Entry) it.next(); + entry.encode(out2); + } + byte[] plaintext = bout.toByteArray(); + byte[] padding = pad.pad(plaintext, 0, plaintext.length); + payload = new byte[plaintext.length + padding.length]; + byte[] lastBlock = new byte[mode.currentBlockSize()]; + int l = mode.currentBlockSize() - padding.length; + System.arraycopy(plaintext, plaintext.length - l, lastBlock, 0, l); + System.arraycopy(padding, 0, lastBlock, l, padding.length); + int count = 0; + while (count + mode.currentBlockSize() < plaintext.length) + { + mode.update(plaintext, count, payload, count); + count += mode.currentBlockSize(); + } + mode.update(lastBlock, 0, payload, count); + } + + public void encodePayload() throws IOException + { + if (payload == null) + throw new IOException("not encrypted"); + } + + private IMode getMode(byte[] key, byte[] iv, int state) + { + IBlockCipher cipher = CipherFactory.getInstance(properties.get("cipher")); + if (cipher == null) + throw new IllegalArgumentException("no such cipher: " + properties.get("cipher")); + int blockSize = cipher.defaultBlockSize(); + if (properties.containsKey("block-size")) + { + try + { + blockSize = Integer.parseInt(properties.get("block-size")); + } + catch (NumberFormatException nfe) + { + throw new IllegalArgumentException("bad block size: " + + nfe.getMessage()); + } + } + IMode mode = ModeFactory.getInstance(properties.get("mode"), cipher, blockSize); + if (mode == null) + throw new IllegalArgumentException("no such mode: " + properties.get("mode")); + + HashMap modeAttr = new HashMap(); + modeAttr.put(IMode.KEY_MATERIAL, key); + modeAttr.put(IMode.STATE, Integer.valueOf(state)); + modeAttr.put(IMode.IV, iv); + try + { + mode.init(modeAttr); + } + catch (InvalidKeyException ike) + { + throw new IllegalArgumentException(ike.toString()); + } + return mode; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/Entry.java b/libjava/classpath/gnu/javax/crypto/keyring/Entry.java new file mode 100644 index 000000000..d45924940 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/Entry.java @@ -0,0 +1,179 @@ +/* Entry.java -- + Copyright (C) 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.crypto.keyring; + +import gnu.java.security.Configuration; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.logging.Logger; + +/** + * An immutable class representing a single entry in a keyring. + */ +public abstract class Entry +{ + private static final Logger log = Logger.getLogger(Entry.class.getName()); + private static final String[] TYPES = new String[] { + "Encrypted", + "PasswordEncrypted", + "Authenticated", + "PasswordAuthenticated", + "Compressed", + "Certificate", + "PublicKey", + "PrivateKey", + "CertPath", + "BinaryData" }; + /** This entry's type identifier. */ + protected int type; + /** This entry's property set. */ + protected Properties properties; + /** This entry's payload. */ + protected byte[] payload; + + /** + * Creates a new Entry. + * + * @param type This entry's type. + * @param properties This entry's properties. + * @throws IllegalArgumentException If the properties argument is null, or if + * the type is out of range. + */ + protected Entry(int type, Properties properties) + { + if (type < 0 || type > 255) + throw new IllegalArgumentException("invalid packet type"); + if (properties == null) + throw new IllegalArgumentException("no properties"); + this.type = type; + this.properties = (Properties) properties.clone(); + } + + /** + * Constructor for use by subclasses. + */ + protected Entry(final int type) + { + if (type < 0 || type > 255) + throw new IllegalArgumentException("invalid packet type"); + this.type = type; + properties = new Properties(); + } + + /** + * Returns this entry's properties object. The properties are cloned before + * being returned. + * + * @return The properties. + */ + public Properties getProperties() + { + return (Properties) properties.clone(); + } + + /** + * Returns this entry's payload data, or null if + */ + public byte[] getPayload() + { + if (payload == null) + return null; + return (byte[]) payload.clone(); + } + + /** + * This method is called when this entry needs to be written to an output + * stream. + * + * @param out The stream to write to. + * @throws IOException If an I/O exception occurs. + */ + public void encode(DataOutputStream out) throws IOException + { + if (payload == null) + encodePayload(); + if (out == null) + return; + out.write(type); + properties.encode(out); + out.writeInt(payload.length); + out.write(payload); + } + + public String toString() + { + return new StringBuilder("Entry{") + .append("type=").append(TYPES[type]) + .append(", properties=").append(properties) + .append(", payload=") + .append(payload == null ? "-" : "byte[" + payload.length + "]") + .append( "}") + .toString(); + } + + /** + * Generic decoding method, which simply decodes the properties field + * and reads the payload field. + * + * @param in The input data stream. + * @throws IOException If an I/O error occurs. + */ + protected void defaultDecode(DataInputStream in) throws IOException + { + properties = new Properties(); + properties.decode(in); + int len = in.readInt(); + if (len < 0) + throw new IOException("corrupt length"); + if (Configuration.DEBUG) + log.fine("About to instantiate new payload byte array for " + this); + payload = new byte[len]; + in.readFully(payload); + } + + /** + * This method is called of subclasses when the payload data needs to be + * created. + * + * @throws IOException If an encoding error occurs. + */ + protected abstract void encodePayload() throws IOException; +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/EnvelopeEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/EnvelopeEntry.java new file mode 100644 index 000000000..76aba7d7b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/EnvelopeEntry.java @@ -0,0 +1,439 @@ +/* EnvelopeEntry.java -- + Copyright (C) 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.crypto.keyring; + +import gnu.java.security.Configuration; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.StringTokenizer; +import java.util.logging.Logger; + +/** + * An envelope entry is a generic container for some number of primitive and + * other envelope entries. + */ +public abstract class EnvelopeEntry + extends Entry +{ + private static final Logger log = Logger.getLogger(EnvelopeEntry.class.getName()); + /** The envelope that contains this one (if any). */ + protected EnvelopeEntry containingEnvelope; + /** The contained entries. */ + protected List entries; + + public EnvelopeEntry(int type, Properties properties) + { + super(type, properties); + entries = new LinkedList(); + if (this.properties.get("alias-list") != null) + this.properties.remove("alias-list"); + } + + protected EnvelopeEntry(int type) + { + super(type); + entries = new LinkedList(); + } + + /** + * Adds an entry to this envelope. + * + * @param entry The entry to add. + */ + public void add(Entry entry) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "add", entry); + if (! containsEntry(entry)) + { + if (entry instanceof EnvelopeEntry) + ((EnvelopeEntry) entry).setContainingEnvelope(this); + entries.add(entry); + if (Configuration.DEBUG) + log.fine("Payload is " + (payload == null ? "" : "not ") + "null"); + makeAliasList(); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "add"); + } + + /** + * Tests if this envelope contains a primitive entry with the given alias. + * + * @param alias The alias to test. + * @return True if this envelope (or one of the contained envelopes) contains + * a primitive entry with the given alias. + */ + public boolean containsAlias(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "containsAlias", alias); + String aliases = getAliasList(); + if (Configuration.DEBUG) + log.fine("aliases = [" + aliases + "]"); + boolean result = false; + if (aliases != null) + { + StringTokenizer tok = new StringTokenizer(aliases, ";"); + while (tok.hasMoreTokens()) + if (tok.nextToken().equals(alias)) + { + result = true; + break; + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "containsAlias", + Boolean.valueOf(result)); + return result; + } + + /** + * Tests if this envelope contains the given entry. + * + * @param entry The entry to test. + * @return True if this envelope contains the given entry. + */ + public boolean containsEntry(Entry entry) + { + if (entry instanceof EnvelopeEntry) + return entries.contains(entry); + if (entry instanceof PrimitiveEntry) + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e.equals(entry)) + return true; + if ((e instanceof EnvelopeEntry) + && ((EnvelopeEntry) e).containsEntry(entry)) + return true; + } + return false; + } + + /** + * Returns a copy of all entries this envelope contains. + * + * @return All contained entries. + */ + public List getEntries() + { + return new ArrayList(entries); + } + + /** + * Gets all primitive entries that have the given alias. If there are any + * masked entries that contain the given alias, they will be returned as well. + * + * @param alias The alias of the entries to get. + * @return A list of all primitive entries that have the given alias. + */ + public List get(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "get", alias); + List result = new LinkedList(); + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof EnvelopeEntry) + { + EnvelopeEntry ee = (EnvelopeEntry) e; + if (! ee.containsAlias(alias)) + continue; + if (ee instanceof MaskableEnvelopeEntry) + { + MaskableEnvelopeEntry mee = (MaskableEnvelopeEntry) ee; + if (mee.isMasked()) + { + if (Configuration.DEBUG) + log.fine("Processing masked entry: " + mee); + result.add(mee); + continue; + } + } + if (Configuration.DEBUG) + log.fine("Processing unmasked entry: " + ee); + result.addAll(ee.get(alias)); + } + else if (e instanceof PrimitiveEntry) + { + PrimitiveEntry pe = (PrimitiveEntry) e; + if (pe.getAlias().equals(alias)) + result.add(e); + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "get", result); + return result; + } + + /** + * Returns the list of all aliases contained by this envelope, separated by a + * semicolon (';'). + * + * @return The list of aliases. + */ + public String getAliasList() + { + String list = properties.get("alias-list"); + if (list == null) + return ""; + else + return list; + } + + /** + * Removes the specified entry. + * + * @param entry The entry. + * @return True if an entry was removed. + */ + public boolean remove(Entry entry) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "remove", entry); + boolean ret = false; + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof EnvelopeEntry) + { + if (e == entry) + { + it.remove(); + ret = true; + break; + } + if (((EnvelopeEntry) e).remove(entry)) + { + ret = true; + break; + } + } + else if (e instanceof PrimitiveEntry) + { + if (((PrimitiveEntry) e).equals(entry)) + { + it.remove(); + ret = true; + break; + } + } + } + if (ret) + { + if (Configuration.DEBUG) + log.fine("State before: " + this); + payload = null; + makeAliasList(); + if (Configuration.DEBUG) + log.fine("State after: " + this); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "remove", Boolean.valueOf(ret)); + return ret; + } + + /** + * Removes all primitive entries that have the specified alias. + * + * @param alias The alias of the entries to remove. + * @return true if alias was present and was + * successfully trmoved. Returns false if + * alias was not present in the list of aliases in this + * envelope. + */ + public boolean remove(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "remove", alias); + boolean result = false; + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof EnvelopeEntry) + { + EnvelopeEntry ee = (EnvelopeEntry) e; + result = ee.remove(alias) || result; + } + else if (e instanceof PrimitiveEntry) + { + PrimitiveEntry pe = (PrimitiveEntry) e; + if (pe.getAlias().equals(alias)) + { + it.remove(); + result = true; + } + } + } + if (result) + { + if (Configuration.DEBUG) + log.fine("State before: " + this); + payload = null; + makeAliasList(); + if (Configuration.DEBUG) + log.fine("State after: " + this); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "remove", Boolean.valueOf(result)); + return result; + } + + public String toString() + { + return new StringBuilder("Envelope{") + .append(super.toString()) + .append(", entries=").append(entries) + .append("}") + .toString(); + } + + // Protected methods. + // ------------------------------------------------------------------------ + + protected void encodePayload() throws IOException + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + DataOutputStream out = new DataOutputStream(bout); + for (Iterator it = entries.iterator(); it.hasNext();) + ((Entry) it.next()).encode(out); + } + + protected void setContainingEnvelope(EnvelopeEntry e) + { + if (containingEnvelope != null) + throw new IllegalArgumentException("envelopes may not be shared"); + containingEnvelope = e; + } + + protected void decodeEnvelope(DataInputStream in) throws IOException + { + this.entries.clear(); + while (true) + { + int type = in.read(); + switch (type) + { + case EncryptedEntry.TYPE: + add(EncryptedEntry.decode(in)); + break; + case PasswordEncryptedEntry.TYPE: + add(PasswordEncryptedEntry.decode(in)); + break; + case PasswordAuthenticatedEntry.TYPE: + add(PasswordAuthenticatedEntry.decode(in)); + break; + case AuthenticatedEntry.TYPE: + add(AuthenticatedEntry.decode(in)); + break; + case CompressedEntry.TYPE: + add(CompressedEntry.decode(in)); + break; + case CertificateEntry.TYPE: + add(CertificateEntry.decode(in)); + break; + case PublicKeyEntry.TYPE: + add(PublicKeyEntry.decode(in)); + break; + case PrivateKeyEntry.TYPE: + add(PrivateKeyEntry.decode(in)); + break; + case CertPathEntry.TYPE: + add(CertPathEntry.decode(in)); + break; + case BinaryDataEntry.TYPE: + add(BinaryDataEntry.decode(in)); + break; + case -1: + return; + default: + throw new MalformedKeyringException("unknown type " + type); + } + } + } + + private void makeAliasList() + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "makeAliasList"); + if (! entries.isEmpty()) + { + StringBuilder buf = new StringBuilder(); + String aliasOrList; + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry entry = (Entry) it.next(); + aliasOrList = null; + if (entry instanceof EnvelopeEntry) + aliasOrList = ((EnvelopeEntry) entry).getAliasList(); + else if (entry instanceof PrimitiveEntry) + aliasOrList = ((PrimitiveEntry) entry).getAlias(); + else if (Configuration.DEBUG) + log.fine("Entry with no Alias. Ignored: " + entry); + if (aliasOrList != null) + { + aliasOrList = aliasOrList.trim(); + if (aliasOrList.trim().length() > 0) + { + buf.append(aliasOrList); + if (it.hasNext()) + buf.append(';'); + } + } + } + String aliasList = buf.toString(); + properties.put("alias-list", aliasList); + if (Configuration.DEBUG) + log.fine("alias-list=[" + aliasList + "]"); + if (containingEnvelope != null) + containingEnvelope.makeAliasList(); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "makeAliasList"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/GnuPrivateKeyring.java b/libjava/classpath/gnu/javax/crypto/keyring/GnuPrivateKeyring.java new file mode 100644 index 000000000..ab3933972 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/GnuPrivateKeyring.java @@ -0,0 +1,368 @@ +/* GnuPrivateKeyring.java -- + Copyright (C) 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.crypto.keyring; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.Key; +import java.security.PublicKey; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.util.Date; +import java.util.Iterator; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + */ +public class GnuPrivateKeyring + extends BaseKeyring + implements IPrivateKeyring +{ + private static final Logger log = Logger.getLogger(GnuPrivateKeyring.class.getName()); + public static final int USAGE = Registry.GKR_PRIVATE_KEYS + | Registry.GKR_PUBLIC_CREDENTIALS; + protected String mac; + protected int maclen; + protected String cipher; + protected String mode; + protected int keylen; + + public GnuPrivateKeyring(String mac, int maclen, String cipher, String mode, + int keylen) + { + keyring = new PasswordAuthenticatedEntry(mac, maclen, new Properties()); + keyring2 = new CompressedEntry(new Properties()); + keyring.add(keyring2); + this.mac = mac; + this.maclen = maclen; + this.cipher = cipher; + this.mode = mode; + this.keylen = keylen; + } + + public GnuPrivateKeyring() + { + this("HMAC-SHA-1", 20, "AES", "OFB", 16); + } + + public boolean containsPrivateKey(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "containsPrivateKey", alias); + boolean result = false; + if (containsAlias(alias)) + for (Iterator it = get(alias).iterator(); it.hasNext();) + if (it.next() instanceof PasswordAuthenticatedEntry) + { + result = true; + break; + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "containsPrivateKey", + Boolean.valueOf(result)); + return result; + } + + public Key getPrivateKey(String alias, char[] password) + throws UnrecoverableKeyException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "getPrivateKey", alias); + Key result = null; + if (containsAlias(alias)) + { + PasswordAuthenticatedEntry e1 = null; + for (Iterator it = get(alias).iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (Configuration.DEBUG) + log.finest("Entry: " + e); + if (e instanceof PasswordAuthenticatedEntry) + { + e1 = (PasswordAuthenticatedEntry) e; + break; + } + } + if (Configuration.DEBUG) + log.fine("e1 = " + e1); + if (e1 != null) + { + try + { + e1.verify(password); + } + catch (Exception e) + { + if (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "getPrivateKey", e); + throw new UnrecoverableKeyException("authentication failed"); + } + PasswordEncryptedEntry e2 = null; + for (Iterator it = e1.getEntries().iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof PasswordEncryptedEntry) + { + e2 = (PasswordEncryptedEntry) e; + break; + } + } + if (e2 != null) + { + try + { + e2.decrypt(password); + } + catch (Exception e) + { + log.throwing(this.getClass().getName(), "getPrivateKey", e); + throw new UnrecoverableKeyException("decryption failed"); + } + for (Iterator it = e2.get(alias).iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof PrivateKeyEntry) + { + result = ((PrivateKeyEntry) e).getKey(); + break; + } + } + } + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "getPrivateKey", + result == null ? "null" : result.getClass().getName()); + return result; + } + + public void putPrivateKey(String alias, Key key, char[] password) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "putPrivateKey", + new Object[] { alias, key.getClass().getName() }); + if (! containsPrivateKey(alias)) + { + alias = fixAlias(alias); + Properties p = new Properties(); + p.put("alias", alias); + PrivateKeyEntry pke = new PrivateKeyEntry(key, new Date(), p); + if (Configuration.DEBUG) + log.fine("About to encrypt the key..."); + PasswordEncryptedEntry enc; + enc = new PasswordEncryptedEntry(cipher, mode, keylen, new Properties()); + enc.add(pke); + try + { + enc.encode(null, password); + } + catch (IOException x) + { + if (Configuration.DEBUG) + log.log(Level.FINE, "Exception while encrypting the key. " + + "Rethrow as IllegalArgumentException", x); + throw new IllegalArgumentException(x.toString()); + } + if (Configuration.DEBUG) + log.fine("About to authenticate the encrypted key..."); + PasswordAuthenticatedEntry auth; + auth = new PasswordAuthenticatedEntry(mac, maclen, new Properties()); + auth.add(enc); + try + { + auth.encode(null, password); + } + catch (IOException x) + { + if (Configuration.DEBUG) + log.log(Level.FINE, "Exception while authenticating the encrypted " + + "key. Rethrow as IllegalArgumentException", x); + throw new IllegalArgumentException(x.toString()); + } + keyring.add(auth); + } + else if (Configuration.DEBUG) + log.fine("Keyring already contains alias: " + alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "putPrivateKey"); + } + + public boolean containsPublicKey(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "containsPublicKey", alias); + boolean result = false; + if (containsAlias(alias)) + for (Iterator it = get(alias).iterator(); it.hasNext();) + if (it.next() instanceof PublicKeyEntry) + { + result = true; + break; + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "containsPublicKey", + Boolean.valueOf(result)); + return result; + } + + public PublicKey getPublicKey(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "getPublicKey", alias); + PublicKey result = null; + if (containsAlias(alias)) + for (Iterator it = get(alias).iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof PublicKeyEntry) + { + result = ((PublicKeyEntry) e).getKey(); + break; + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "getPublicKey", + result == null ? "null" : result.getClass().getName()); + return result; + } + + public void putPublicKey(String alias, PublicKey key) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "putPublicKey", + new Object[] { alias, key.getClass().getName() }); + if (! containsPublicKey(alias)) + { + Properties p = new Properties(); + p.put("alias", fixAlias(alias)); + add(new PublicKeyEntry(key, new Date(), p)); + } + else if (Configuration.DEBUG) + log.fine("Keyring already contains alias: " + alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "putPublicKey"); + } + + public boolean containsCertPath(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "containsCertPath", alias); + boolean result = false; + if (containsAlias(alias)) + for (Iterator it = get(alias).iterator(); it.hasNext();) + if (it.next() instanceof CertPathEntry) + { + result = true; + break; + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "containsCertPath", + Boolean.valueOf(result)); + return result; + } + + public Certificate[] getCertPath(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "getCertPath", alias); + Certificate[] result = null; + if (containsAlias(alias)) + for (Iterator it = get(alias).iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof CertPathEntry) + { + result = ((CertPathEntry) e).getCertPath(); + break; + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "getCertPath", result); + return result; + } + + public void putCertPath(String alias, Certificate[] path) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "putCertPath", + new Object[] { alias, path }); + if (! containsCertPath(alias)) + { + Properties p = new Properties(); + p.put("alias", fixAlias(alias)); + add(new CertPathEntry(path, new Date(), p)); + } + else if (Configuration.DEBUG) + log.fine("Keyring already contains alias: " + alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "putCertPath"); + } + + protected void load(InputStream in, char[] password) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "load"); + if (in.read() != USAGE) + throw new MalformedKeyringException("incompatible keyring usage"); + if (in.read() != PasswordAuthenticatedEntry.TYPE) + throw new MalformedKeyringException( + "expecting password-authenticated entry tag"); + keyring = PasswordAuthenticatedEntry.decode(new DataInputStream(in), password); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "load"); + } + + protected void store(OutputStream out, char[] password) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "store"); + out.write(USAGE); + keyring.encode(new DataOutputStream(out), password); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "store"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/GnuPublicKeyring.java b/libjava/classpath/gnu/javax/crypto/keyring/GnuPublicKeyring.java new file mode 100644 index 000000000..d7387f892 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/GnuPublicKeyring.java @@ -0,0 +1,151 @@ +/* GnuPublicKeyring.java -- + Copyright (C) 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.crypto.keyring; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.cert.Certificate; +import java.util.Date; +import java.util.Iterator; +import java.util.logging.Logger; + +public class GnuPublicKeyring + extends BaseKeyring + implements IPublicKeyring +{ + private static final Logger log = Logger.getLogger(GnuPublicKeyring.class.getName()); + public static final int USAGE = Registry.GKR_CERTIFICATES; + + public GnuPublicKeyring(String mac, int macLen) + { + keyring = new PasswordAuthenticatedEntry(mac, macLen, new Properties()); + keyring2 = new CompressedEntry(new Properties()); + keyring.add(keyring2); + } + + public GnuPublicKeyring() + { + } + + public boolean containsCertificate(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "containsCertificate", alias); + boolean result = false; + if (containsAlias(alias)) + for (Iterator it = get(alias).iterator(); it.hasNext();) + if (it.next() instanceof CertificateEntry) + { + result = true; + break; + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "containsCertificate", + Boolean.valueOf(result)); + return result; + } + + public Certificate getCertificate(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "getCertificate", alias); + Certificate result = null; + if (containsAlias(alias)) + for (Iterator it = get(alias).iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof CertificateEntry) + { + result = ((CertificateEntry) e).getCertificate(); + break; + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "getCertificate", result); + return result; + } + + public void putCertificate(String alias, Certificate cert) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "putCertificate", + new Object[] { alias, cert }); + if (! containsCertificate(alias)) + { + Properties p = new Properties(); + p.put("alias", fixAlias(alias)); + add(new CertificateEntry(cert, new Date(), p)); + } + else if (Configuration.DEBUG) + log.fine("Keyring already contains alias: " + alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "putCertificate"); + } + + protected void load(InputStream in, char[] password) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "load"); + if (in.read() != USAGE) + throw new MalformedKeyringException("incompatible keyring usage"); + if (in.read() != PasswordAuthenticatedEntry.TYPE) + throw new MalformedKeyringException( + "expecting password-authenticated entry tag"); + DataInputStream dis = new DataInputStream(in); + keyring = PasswordAuthenticatedEntry.decode(dis, password); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "load"); + } + + protected void store(OutputStream out, char[] password) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "store"); + out.write(USAGE); + keyring.encode(new DataOutputStream(out), password); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "store"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/IKeyring.java b/libjava/classpath/gnu/javax/crypto/keyring/IKeyring.java new file mode 100644 index 000000000..141f2dcd4 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/IKeyring.java @@ -0,0 +1,162 @@ +/* IKeyring.java -- + Copyright (C) 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.crypto.keyring; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; + +/** + * The top-level interface to a keyring: a file that is used to store + * and protect public and private cryptographic keys. + *

+ * A keyring is modelled as a mapping of one alias to one or + * more entries (optionally of different types). + *

+ * See also the sub-interfaces {@link IPublicKeyring} and + * {@link IPrivateKeyring} for special types of keyrings --the + * difference being in the type of entries they contain. + */ +public interface IKeyring +{ + /** + * Property name for the source of data to load the keyring from. The value + * mapped must be a {@link java.io.InputStream}. + */ + public static final String KEYRING_DATA_IN = "gnu.crypto.keyring.data.in"; + + /** + * Property name for the data sink to store the keyring to. The value mapped + * must be a {@link java.io.OutputStream}. + */ + public static final String KEYRING_DATA_OUT = "gun.crypto.keyring.data.out"; + + /** + * Property name for the keyring's top-level password, used to authenticate + * and/or transform the store itself. The mapped value must be a char array. + */ + public static final String KEYRING_PASSWORD = "gnu.crypto.keyring.password"; + + /** + * Loads a keyring into memory. + *

+ * What happens to the current contents of this keyring? are the new ones + * merged with the current ones or do they simply replace them? + * + * @param attributes The attributes that designate the source where the store + * is to be loaded from. What happens + * @throws IllegalArgumentException If the attributes are inappropriate. + * @throws IOException If the keyring file cannot be read. + * @throws SecurityException If the given password is incorrect, or if the + * top-level authentication or decryption fails. + */ + void load(Map attributes) throws IOException; + + /** + * Stores the contents of this keyring to persistent storage as specified by + * the designated attributes. + * + * @param attributes the attributes that define where the contents of this + * keyring will be stored. + * @throws IOException if an exception occurs during the process. + */ + void store(Map attributes) throws IOException; + + /** + * Resets this keyring, clearing all sensitive data. This method always + * suceeds. + */ + void reset(); + + /** + * Returns the number of entries in this keyring. + * + * @return The number of current entries in this keyring. + */ + int size(); + + /** + * Returns an {@link Enumeration} of all aliases (instances of {@link String}) + * in this keyring. + * + * @return The enumeration of {@link String}s each representing an alias + * found in this keyring. + */ + Enumeration aliases(); + + /** + * Tests whether or not this keyring contains the given alias. + * + * @param alias The alias to check. + * @return true if this keyring contains the alias. + */ + boolean containsAlias(String alias); + + /** + * Returns a {@link List} of entries (instances of {@link Entry}) for the + * given alias, or null if there no such entry + * exists. + * + * @param alias The alias of the entry(ies) to return. + * @return A list of all entries (instances of {@link Entry} that have the + * given alias, or null if no one + * {@link Entry} can be found with the designated alias. + */ + List get(String alias); + + /** + * Adds a designated {@link Entry} to this keyring. + *

+ * What happens if there is already an entry with the same alias? + * + * @param entry The entry to put in this keyring. + */ + void add(Entry entry); + + /** + * Removes an entry with the designated alias from this + * keyring. Does nothing if there was no such entry. + *

+ * What happens if there are more than one? + * + * @param alias The alias of the entry to remove. + */ + void remove(String alias); +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/IPrivateKeyring.java b/libjava/classpath/gnu/javax/crypto/keyring/IPrivateKeyring.java new file mode 100644 index 000000000..3bfa10098 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/IPrivateKeyring.java @@ -0,0 +1,144 @@ +/* IPrivateKeyring.java -- + Copyright (C) 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.crypto.keyring; + +import java.security.Key; +import java.security.PublicKey; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; + +/** + * An interface to private, or "personal", keyrings, which contain private + * credentials. The contract is that each such entry is known by a unique + * alias. + *

+ * What about public keys? and certificate-path? + */ +public interface IPrivateKeyring + extends IKeyring +{ + /** + * Tests if this keyring contains a private key entry with the given + * alias. + * + * @param alias The alias to check. + * @return true if this keyring contains a private key with the + * given alias; false otherwise. + */ + boolean containsPrivateKey(String alias); + + /** + * Returns the private key with the given alias. + * + * @param alias The alias of the private key to find. + * @param password The password of the private key. + * @return The private, or secret, key if one is found; null if + * none were found. + * @throws UnrecoverableKeyException If the private key could not be + * recovered, possibly due to a bad password. + */ + Key getPrivateKey(String alias, char[] password) + throws UnrecoverableKeyException; + + /** + * Adds a private key to this keyring. + * + * @param alias The alias of the private key. + * @param key The private key. + * @param password The password used to protect this private key. + */ + void putPrivateKey(String alias, Key key, char[] password); + + /** + * Checks if this keyring contains a public key with the given + * alias. + * + * @param alias The alias to test. + * @return true if this keyring contains a public key entry + * with the given alias; false + * otherwise. + */ + boolean containsPublicKey(String alias); + + /** + * Returns the public key with the given alias, or + * null if there is no such entry. + * + * @param alias The alias of the public key to find. + * @return The public key; or null if none were found. + */ + PublicKey getPublicKey(String alias); + + /** + * Sets a public key entry. + * + * @param alias The alias for this public key. + * @param key The public key. + */ + void putPublicKey(String alias, PublicKey key); + + /** + * Checks if this keyring contains a certificate path with the given + * alias. + * + * @param alias The alias to check. + * @return true if this keyring contains a certificate path + * with the given alias; false + * otherwise. + */ + boolean containsCertPath(String alias); + + /** + * Returns the certificate path with the given alias, or + * null if there is no such entry. + * + * @param alias The alias of the certificate path to find. + * @return The certificate path for the designated alias; or + * null if none were found. + */ + Certificate[] getCertPath(String alias); + + /** + * Sets a certificate path entry. + * + * @param alias The alias for this certificate path. + * @param path The certificate path. + */ + void putCertPath(String alias, Certificate[] path); +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/IPublicKeyring.java b/libjava/classpath/gnu/javax/crypto/keyring/IPublicKeyring.java new file mode 100644 index 000000000..d723f5ae9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/IPublicKeyring.java @@ -0,0 +1,82 @@ +/* IPublicKeyring.java -- + Copyright (C) 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.crypto.keyring; + +import java.security.cert.Certificate; + +/** + * An interface for keyrings that contain trusted (by the owner) public + * credentials (incl. certificates). + * + * @see IKeyring + */ +public interface IPublicKeyring + extends IKeyring +{ + /** + * Tests if this keyring contains a certificate entry with the specified + * alias. + * + * @param alias The alias of the certificate to check. + * @return true if this keyring contains a certificate entry + * that has the given alias; false + * otherwise. + */ + boolean containsCertificate(String alias); + + /** + * Returns a certificate that has the given alias, or + * null if this keyring has no such entry. + * + * @param alias The alias of the certificate to find. + * @return The certificate with the designated alias, or + * null if none found. + */ + Certificate getCertificate(String alias); + + /** + * Adds a certificate in this keyring, with the given alias. + *

+ * What happens if there is already a certificate entry with this alias? + * + * @param alias The alias of this certificate entry. + * @param cert The certificate. + */ + void putCertificate(String alias, Certificate cert); +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/MalformedKeyringException.java b/libjava/classpath/gnu/javax/crypto/keyring/MalformedKeyringException.java new file mode 100644 index 000000000..f6b9d189b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/MalformedKeyringException.java @@ -0,0 +1,55 @@ +/* MalformedKeyringException.java -- + Copyright (C) 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.crypto.keyring; + +import java.io.IOException; + +public class MalformedKeyringException + extends IOException +{ + public MalformedKeyringException() + { + super(); + } + + public MalformedKeyringException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java new file mode 100644 index 000000000..58254a437 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java @@ -0,0 +1,135 @@ +/* MaskableEnvelopeEntry.java -- + Copyright (C) 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.crypto.keyring; + +import java.util.ArrayList; +import java.util.List; + +/** + * An envelope entry that can be "masked" -- placed in a state where the + * envelope's contents cannot be accessed, due to the envelope not being fully + * decoded, for example. + */ +public abstract class MaskableEnvelopeEntry + extends EnvelopeEntry +{ + /** The masked state. */ + protected boolean masked; + + public MaskableEnvelopeEntry(int type, Properties properties) + { + super(type, properties); + } + + protected MaskableEnvelopeEntry(int type) + { + super(type); + } + + /** + * Sets the masked state to the specified value. + * + * @param masked The new masked state. + */ + protected final void setMasked(boolean masked) + { + this.masked = masked; + } + + /** + * Gets the masked state of this object. Certain operations on this object + * will fail if it is masked. + * + * @return The current masked state. + */ + public boolean isMasked() + { + return masked; + } + + public void add(Entry entry) + { + if (isMasked()) + throw new IllegalStateException("masked envelope"); + super.add(entry); + } + + public boolean containsEntry(Entry entry) + { + if (isMasked()) + throw new IllegalStateException("masked envelope"); + return super.containsEntry(entry); + } + + public List getEntries() + { + if (isMasked()) + throw new IllegalStateException("masked envelope"); + return new ArrayList(entries); + } + + public List get(String alias) + { + if (isMasked()) + throw new IllegalStateException("masked envelope"); + return super.get(alias); + } + + public boolean remove(Entry entry) + { + if (isMasked()) + throw new IllegalStateException("masked envelope"); + return super.remove(entry); + } + + public boolean remove(String alias) + { + if (isMasked()) + throw new IllegalStateException("masked envelope"); + return super.remove(alias); + } + + public String toString() + { + return new StringBuilder("MaskableEnvelope{") + .append(super.toString()) + .append(", masked=").append(masked) + .append("}").toString(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/MeteredInputStream.java b/libjava/classpath/gnu/javax/crypto/keyring/MeteredInputStream.java new file mode 100644 index 000000000..65f263359 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/MeteredInputStream.java @@ -0,0 +1,127 @@ +/* MeteredInputStream.java -- + Copyright (C) 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.crypto.keyring; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +final class MeteredInputStream + extends FilterInputStream +{ + private int count; + private final int limit; + + MeteredInputStream(InputStream in, int limit) + { + super(in); + if (limit < 0) + throw new IllegalArgumentException("limit must be nonnegative"); + this.limit = limit; + count = 0; + } + + /** + * Tests if the number of bytes read has reached the limit. + * + * @return True if the limit has been reached. + */ + public boolean limitReached() + { + return count == limit; + } + + public int available() throws IOException + { + return Math.min(in.available(), limit - count); + } + + public void close() throws IOException + { + in.close(); + } + + public void mark(int readLimit) + { + } + + public boolean markSupported() + { + return false; + } + + public int read() throws IOException + { + if (limitReached()) + return -1; + int i = in.read(); + if (i != -1) + count++; + 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 + { + if (limitReached()) + return -1; + int i = in.read(buf, off, Math.min(len, limit - count)); + if (i != -1) + count += i; + return i; + } + + public void reset() throws IOException + { + } + + public long skip(long len) throws IOException + { + if (limitReached()) + return 0L; + len = Math.min(len, limit - count); + len = in.skip(len); + count += (int) len; + return len; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java new file mode 100644 index 000000000..d67300442 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java @@ -0,0 +1,286 @@ +/* PasswordAuthenticatedEntry.java -- + Copyright (C) 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.crypto.keyring; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.PRNG; +import gnu.java.security.util.Util; +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; +import gnu.javax.crypto.mac.MacInputStream; +import gnu.javax.crypto.mac.MacOutputStream; +import gnu.javax.crypto.prng.IPBE; +import gnu.javax.crypto.prng.PRNGFactory; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.security.InvalidKeyException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.logging.Logger; + +/** + * An entry authenticated with a password-based MAC. + */ +public final class PasswordAuthenticatedEntry + extends MaskableEnvelopeEntry + implements PasswordProtectedEntry, Registry +{ + private static final Logger log = Logger.getLogger(PasswordAuthenticatedEntry.class.getName()); + public static final int TYPE = 3; + + public PasswordAuthenticatedEntry(String mac, int maclen, + Properties properties) + { + super(TYPE, properties); + if (mac == null || mac.length() == 0) + throw new IllegalArgumentException("no MAC specified"); + this.properties.put("mac", mac); + this.properties.put("maclen", String.valueOf(maclen)); + setMasked(false); + } + + private PasswordAuthenticatedEntry() + { + super(TYPE); + setMasked(true); + } + + public static PasswordAuthenticatedEntry decode(DataInputStream in, + char[] password) + throws IOException + { + PasswordAuthenticatedEntry entry = new PasswordAuthenticatedEntry(); + entry.properties.decode(in); + IMac mac = entry.getMac(password); + int len = in.readInt() - mac.macSize(); + MeteredInputStream min = new MeteredInputStream(in, len); + MacInputStream macin = new MacInputStream(min, mac); + DataInputStream in2 = new DataInputStream(macin); + entry.setMasked(false); + entry.decodeEnvelope(in2); + byte[] macValue = new byte[mac.macSize()]; + in.readFully(macValue); + if (! Arrays.equals(macValue, mac.digest())) + throw new MalformedKeyringException("MAC verification failed"); + return entry; + } + + public static PasswordAuthenticatedEntry decode(DataInputStream in) + throws IOException + { + PasswordAuthenticatedEntry entry = new PasswordAuthenticatedEntry(); + entry.defaultDecode(in); + if (! entry.properties.containsKey("mac")) + throw new MalformedKeyringException("no MAC"); + if (! entry.properties.containsKey("maclen")) + throw new MalformedKeyringException("no MAC length"); + if (! entry.properties.containsKey("salt")) + throw new MalformedKeyringException("no salt"); + return entry; + } + + public void verify(char[] password) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "verify"); + if (isMasked() && payload != null) + { + if (Configuration.DEBUG) + log.fine("payload to verify: " + Util.dumpString(payload)); + long tt = -System.currentTimeMillis(); + IMac m = null; + try + { + m = getMac(password); + } + catch (Exception x) + { + throw new IllegalArgumentException(x.toString(), x); + } + int limit = payload.length - m.macSize(); + m.update(payload, 0, limit); + byte[] macValue = new byte[m.macSize()]; + System.arraycopy(payload, payload.length - macValue.length, macValue, + 0, macValue.length); + if (! Arrays.equals(macValue, m.digest())) + throw new IllegalArgumentException("MAC verification failed"); + setMasked(false); + ByteArrayInputStream bais; + try + { + bais = new ByteArrayInputStream(payload, 0, limit); + DataInputStream in = new DataInputStream(bais); + decodeEnvelope(in); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("malformed keyring fragment"); + } + tt += System.currentTimeMillis(); + if (Configuration.DEBUG) + log.fine("Verified in " + tt + "ms."); + } + else if (Configuration.DEBUG) + log.fine("Skip verification; " + + (isMasked() ? "null payload" : "unmasked")); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "verify"); + } + + public void authenticate(char[] password) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "authenticate"); + long tt = -System.currentTimeMillis(); + long t1 = -System.currentTimeMillis(); + if (isMasked()) + throw new IllegalStateException("entry is masked"); + byte[] salt = new byte[8]; + PRNG.getInstance().nextBytes(salt); + t1 += System.currentTimeMillis(); + if (Configuration.DEBUG) + log.fine("-- Generated salt in " + t1 + "ms."); + properties.put("salt", Util.toString(salt)); + IMac m = getMac(password); + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + MacOutputStream macout = new MacOutputStream(bout, m); + DataOutputStream out2 = new DataOutputStream(macout); + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry entry = (Entry) it.next(); + if (Configuration.DEBUG) + log.fine("-- About to authenticate one " + entry); + t1 = -System.currentTimeMillis(); + entry.encode(out2); + t1 += System.currentTimeMillis(); + if (Configuration.DEBUG) + log.fine("-- Authenticated an Entry in " + t1 + "ms."); + } + bout.write(m.digest()); + payload = bout.toByteArray(); + if (Configuration.DEBUG) + log.fine("authenticated payload: " + Util.dumpString(payload)); + setMasked(true); + tt += System.currentTimeMillis(); + if (Configuration.DEBUG) + { + log.fine("Authenticated in " + tt + "ms."); + log.exiting(this.getClass().getName(), "authenticate"); + } + } + + public void encode(DataOutputStream out, char[] password) throws IOException + { + authenticate(password); + encode(out); + } + + protected void encodePayload(DataOutputStream out) throws IOException + { + if (payload == null) + { + log.fine("Null payload: " + this); + throw new IllegalStateException("mac not computed"); + } + } + + private IMac getMac(char[] password) throws MalformedKeyringException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "getMac"); + String saltString = properties.get("salt"); + if (saltString == null) + throw new MalformedKeyringException("no salt"); + byte[] salt = Util.toBytesFromString(saltString); + String macAlgorithm = properties.get("mac"); + IMac mac = MacFactory.getInstance(macAlgorithm); + if (mac == null) + throw new MalformedKeyringException("no such mac: " + macAlgorithm); + String macLenString = properties.get("maclen"); + if (macLenString == null) + throw new MalformedKeyringException("no MAC length"); + int maclen; + try + { + maclen = Integer.parseInt(macLenString); + } + catch (NumberFormatException nfe) + { + throw new MalformedKeyringException("bad MAC length"); + } + HashMap pbAttr = new HashMap(); + pbAttr.put(IPBE.PASSWORD, password); + pbAttr.put(IPBE.SALT, salt); + pbAttr.put(IPBE.ITERATION_COUNT, ITERATION_COUNT); + IRandom kdf = PRNGFactory.getInstance("PBKDF2-HMAC-SHA"); + kdf.init(pbAttr); + int keylen = mac.macSize(); + byte[] dk = new byte[keylen]; + try + { + kdf.nextBytes(dk, 0, keylen); + } + catch (LimitReachedException shouldNotHappen) + { + throw new Error(shouldNotHappen.toString()); + } + HashMap macAttr = new HashMap(); + macAttr.put(IMac.MAC_KEY_MATERIAL, dk); + macAttr.put(IMac.TRUNCATED_SIZE, Integer.valueOf(maclen)); + try + { + mac.init(macAttr); + } + catch (InvalidKeyException shouldNotHappen) + { + throw new Error(shouldNotHappen.toString()); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "getMac"); + return mac; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java new file mode 100644 index 000000000..0fa7431a8 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java @@ -0,0 +1,293 @@ +/* PasswordEncryptedEntry.java -- + Copyright (C) 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.crypto.keyring; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.PRNG; +import gnu.java.security.util.Util; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.mode.ModeFactory; +import gnu.javax.crypto.pad.IPad; +import gnu.javax.crypto.pad.PadFactory; +import gnu.javax.crypto.pad.WrongPaddingException; +import gnu.javax.crypto.prng.IPBE; +import gnu.javax.crypto.prng.PRNGFactory; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.security.InvalidKeyException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.logging.Logger; + +/** + * An envelope that is encrypted with a password-derived key. + */ +public class PasswordEncryptedEntry + extends MaskableEnvelopeEntry + implements PasswordProtectedEntry, Registry +{ + private static final Logger log = Logger.getLogger(PasswordEncryptedEntry.class.getName()); + public static final int TYPE = 1; + + public PasswordEncryptedEntry(String cipher, String mode, int keylen, + Properties properties) + { + super(TYPE, properties); + if ((cipher == null || cipher.length() == 0) + || (mode == null || mode.length() == 0)) + throw new IllegalArgumentException("cipher nor mode can be empty"); + this.properties.put("cipher", cipher); + this.properties.put("mode", mode); + this.properties.put("keylen", String.valueOf(keylen)); + setMasked(false); + } + + private PasswordEncryptedEntry() + { + super(TYPE); + setMasked(true); + } + + public static PasswordEncryptedEntry decode(DataInputStream in, + char[] password) + throws IOException + { + PasswordEncryptedEntry entry = decode(in); + try + { + entry.decrypt(password); + } + catch (WrongPaddingException wpe) + { + throw new MalformedKeyringException("wrong padding in decrypted data"); + } + return entry; + } + + public static PasswordEncryptedEntry decode(DataInputStream in) + throws IOException + { + PasswordEncryptedEntry entry = new PasswordEncryptedEntry(); + entry.defaultDecode(in); + return entry; + } + + public void decrypt(char[] password) throws IllegalArgumentException, + WrongPaddingException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "decrypt"); + if (isMasked() && payload != null) + { + long tt = -System.currentTimeMillis(); + IMode mode = getMode(password, IMode.DECRYPTION); + IPad padding = PadFactory.getInstance("PKCS7"); + padding.init(mode.currentBlockSize()); + byte[] buf = new byte[payload.length]; + int count = 0; + while (count + mode.currentBlockSize() <= payload.length) + { + mode.update(payload, count, buf, count); + count += mode.currentBlockSize(); + } + int padlen = padding.unpad(buf, 0, buf.length); + setMasked(false); + int len = buf.length - padlen; + ByteArrayInputStream baos = new ByteArrayInputStream(buf, 0, len); + DataInputStream in = new DataInputStream(baos); + try + { + decodeEnvelope(in); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("decryption failed"); + } + tt += System.currentTimeMillis(); + log.fine("Decrypted in " + tt + "ms."); + } + else if (Configuration.DEBUG) + log.fine("Skip decryption; " + (isMasked() ? "null payload" : "unmasked")); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "decrypt"); + } + + public void encrypt(char[] password) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "encrypt", String.valueOf(password)); + long tt = -System.currentTimeMillis(); + long t1 = -System.currentTimeMillis(); + byte[] salt = new byte[8]; + PRNG.getInstance().nextBytes(salt); + t1 += System.currentTimeMillis(); + if (Configuration.DEBUG) + log.fine("-- Generated salt in " + t1 + "ms."); + properties.put("salt", Util.toString(salt)); + IMode mode = getMode(password, IMode.ENCRYPTION); + IPad pad = PadFactory.getInstance("PKCS7"); + pad.init(mode.currentBlockSize()); + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + DataOutputStream out2 = new DataOutputStream(bout); + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry entry = (Entry) it.next(); + if (Configuration.DEBUG) + log.fine("-- About to encode one " + entry); + t1 = -System.currentTimeMillis(); + entry.encode(out2); + t1 += System.currentTimeMillis(); + if (Configuration.DEBUG) + log.fine("-- Encoded an Entry in " + t1 + "ms."); + } + byte[] plaintext = bout.toByteArray(); + byte[] padding = pad.pad(plaintext, 0, plaintext.length); + payload = new byte[plaintext.length + padding.length]; + byte[] lastBlock = new byte[mode.currentBlockSize()]; + int l = mode.currentBlockSize() - padding.length; + System.arraycopy(plaintext, plaintext.length - l, lastBlock, 0, l); + System.arraycopy(padding, 0, lastBlock, l, padding.length); + int count = 0; + while (count + mode.currentBlockSize() < plaintext.length) + { + mode.update(plaintext, count, payload, count); + count += mode.currentBlockSize(); + } + mode.update(lastBlock, 0, payload, count); + setMasked(true); + tt += System.currentTimeMillis(); + if (Configuration.DEBUG) + { + log.fine("Encrypted in " + tt + "ms."); + log.exiting(this.getClass().getName(), "encrypt"); + } + } + + public void encode(DataOutputStream out, char[] password) throws IOException + { + encrypt(password); + encode(out); + } + + protected void encodePayload() throws IOException + { + if (payload == null) + { + if (Configuration.DEBUG) + log.fine("Null payload: " + this); + throw new IllegalStateException("not encrypted"); + } + } + + private IMode getMode(char[] password, int state) + { + String s = properties.get("salt"); + if (s == null) + throw new IllegalArgumentException("no salt"); + byte[] salt = Util.toBytesFromString(s); + IBlockCipher cipher = CipherFactory.getInstance(properties.get("cipher")); + if (cipher == null) + throw new IllegalArgumentException("no such cipher: " + + properties.get("cipher")); + int blockSize = cipher.defaultBlockSize(); + if (properties.containsKey("block-size")) + try + { + blockSize = Integer.parseInt(properties.get("block-size")); + } + catch (NumberFormatException nfe) + { + throw new IllegalArgumentException("bad block size: " + + nfe.getMessage()); + } + String modeName = properties.get("mode"); + IMode mode = ModeFactory.getInstance(modeName, cipher, blockSize); + if (mode == null) + throw new IllegalArgumentException("no such mode: " + modeName); + HashMap pbAttr = new HashMap(); + pbAttr.put(IPBE.PASSWORD, password); + pbAttr.put(IPBE.SALT, salt); + pbAttr.put(IPBE.ITERATION_COUNT, ITERATION_COUNT); + IRandom kdf = PRNGFactory.getInstance("PBKDF2-HMAC-SHA"); + kdf.init(pbAttr); + int keylen = 0; + if (! properties.containsKey("keylen")) + throw new IllegalArgumentException("no key length"); + try + { + keylen = Integer.parseInt(properties.get("keylen")); + } + catch (NumberFormatException nfe) + { + } + byte[] dk = new byte[keylen]; + byte[] iv = new byte[blockSize]; + try + { + kdf.nextBytes(dk, 0, keylen); + kdf.nextBytes(iv, 0, blockSize); + } + catch (LimitReachedException shouldNotHappen) + { + throw new Error(shouldNotHappen.toString()); + } + HashMap modeAttr = new HashMap(); + modeAttr.put(IMode.KEY_MATERIAL, dk); + modeAttr.put(IMode.STATE, Integer.valueOf(state)); + modeAttr.put(IMode.IV, iv); + try + { + mode.init(modeAttr); + } + catch (InvalidKeyException ike) + { + throw new IllegalArgumentException(ike.toString()); + } + return mode; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/PasswordProtectedEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/PasswordProtectedEntry.java new file mode 100644 index 000000000..a95f2e4a4 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/PasswordProtectedEntry.java @@ -0,0 +1,57 @@ +/* PasswordProtectedEntry.java -- + Copyright (C) 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.crypto.keyring; + +import java.io.DataOutputStream; +import java.io.IOException; + +public interface PasswordProtectedEntry +{ + /** The iteration count for password-based KDFs. */ + Integer ITERATION_COUNT = Integer.valueOf(1000); + + /** + * Encodes this entry, protected by a password. + * + * @param out The output stream to encode to. + * @param password The password. + * @throws IOException If an I/O error occurs. + */ + void encode(DataOutputStream out, char[] password) throws IOException; +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/PrimitiveEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/PrimitiveEntry.java new file mode 100644 index 000000000..8993de716 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/PrimitiveEntry.java @@ -0,0 +1,112 @@ +/* PrimitiveEntry.java -- + Copyright (C) 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.crypto.keyring; + +import java.util.Date; + +/** + * A primitive entry is an entry that contains a single cryptographic entity. + */ +public abstract class PrimitiveEntry + extends Entry +{ + /** The creation date. */ + protected Date creationDate; + + protected PrimitiveEntry(int type, Date creationDate, Properties properties) + { + super(type, properties); + if (creationDate == null) + this.creationDate = new Date(); + else + this.creationDate = (Date) creationDate.clone(); + if (! this.properties.containsKey("alias") + || this.properties.get("alias").length() == 0) + throw new IllegalArgumentException("primitive entries MUST have an alias"); + this.properties.put("creation-date", + String.valueOf(this.creationDate.getTime())); + } + + protected PrimitiveEntry(int type) + { + super(type); + } + + /** + * Returns the alias of this primitive entry. + * + * @return The alias. + */ + public String getAlias() + { + return properties.get("alias"); + } + + /** + * Returns the creation date of this primitive entry. + * + * @return The creation date. + */ + public Date getCreationDate() + { + return (Date) creationDate.clone(); + } + + public boolean equals(Object object) + { + if (! getClass().equals(object.getClass())) + return false; + return getAlias().equals(((PrimitiveEntry) object).getAlias()); + } + + protected final void makeCreationDate() throws MalformedKeyringException + { + String s = properties.get("creation-date"); + if (s == null) + throw new MalformedKeyringException("no creation date"); + try + { + creationDate = new Date(Long.parseLong(s)); + } + catch (NumberFormatException nfe) + { + throw new MalformedKeyringException("invalid creation date"); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/PrivateKeyEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/PrivateKeyEntry.java new file mode 100644 index 000000000..b2637316e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/PrivateKeyEntry.java @@ -0,0 +1,194 @@ +/* PrivateKeyEntry.java -- + Copyright (C) 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.crypto.keyring; + +import gnu.java.security.key.IKeyPairCodec; +import gnu.java.security.key.KeyPairCodecFactory; +import gnu.java.security.key.dss.DSSPrivateKey; +import gnu.java.security.key.rsa.GnuRSAPrivateKey; +import gnu.javax.crypto.key.GnuSecretKey; +import gnu.javax.crypto.key.dh.GnuDHPrivateKey; + +import java.io.DataInputStream; +import java.io.IOException; +import java.security.Key; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.util.Date; + +/** + * An immutable class representing a private or secret key entry. + */ +public final class PrivateKeyEntry + extends PrimitiveEntry +{ + public static final int TYPE = 7; + /** The key. */ + private Key key; + + /** + * Creates a new key entry. + * + * @param key The key. + * @param creationDate The entry creation date. + * @param properties The entry properties. + * @throws IllegalArgumentException If any parameter is null. + */ + public PrivateKeyEntry(Key key, Date creationDate, Properties properties) + { + super(TYPE, creationDate, properties); + if (key == null) + throw new IllegalArgumentException("no private key"); + if (! (key instanceof PrivateKey) && ! (key instanceof GnuSecretKey)) + throw new IllegalArgumentException("not a private or secret key"); + this.key = key; + } + + private PrivateKeyEntry() + { + super(TYPE); + } + + public static PrivateKeyEntry decode(DataInputStream in) throws IOException + { + PrivateKeyEntry entry = new PrivateKeyEntry(); + entry.defaultDecode(in); + String type = entry.properties.get("type"); + if (type == null) + throw new MalformedKeyringException("no key type"); + if (type.equalsIgnoreCase("RAW-DSS")) + { + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dss"); + entry.key = coder.decodePrivateKey(entry.payload); + } + else if (type.equalsIgnoreCase("RAW-RSA")) + { + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("rsa"); + entry.key = coder.decodePrivateKey(entry.payload); + } + else if (type.equalsIgnoreCase("RAW-DH")) + { + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dh"); + entry.key = coder.decodePrivateKey(entry.payload); + } + else if (type.equalsIgnoreCase("RAW")) + entry.key = new GnuSecretKey(entry.payload, null); + else if (type.equalsIgnoreCase("PKCS8")) + { + try + { + KeyFactory kf = KeyFactory.getInstance("RSA"); + PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(entry.payload); + entry.key = kf.generatePrivate(ks); + } + catch (Exception ignored) + { + } + if (entry.key == null) + { + try + { + KeyFactory kf = KeyFactory.getInstance("DSA"); + PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(entry.payload); + entry.key = kf.generatePrivate(ks); + } + catch (Exception ignored) + { + } + if (entry.key == null) + throw new MalformedKeyringException("could not decode PKCS#8 key"); + } + } + else + throw new MalformedKeyringException("unsupported key type " + type); + return entry; + } + + /** + * Returns this entry's key. + * + * @return The key. + */ + public Key getKey() + { + return key; + } + + protected void encodePayload() throws IOException + { + String format = key.getFormat(); + if (key instanceof DSSPrivateKey) + { + properties.put("type", "RAW-DSS"); + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dss"); + payload = coder.encodePrivateKey((PrivateKey) key); + } + else if (key instanceof GnuRSAPrivateKey) + { + properties.put("type", "RAW-RSA"); + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("rsa"); + payload = coder.encodePrivateKey((PrivateKey) key); + } + else if (key instanceof GnuDHPrivateKey) + { + properties.put("type", "RAW-DH"); + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dh"); + payload = coder.encodePrivateKey((PrivateKey) key); + } + else if (key instanceof GnuSecretKey) + { + properties.put("type", "RAW"); + payload = key.getEncoded(); + } + else if (format != null && format.equals("PKCS#8")) + { + properties.put("type", "PKCS8"); + payload = key.getEncoded(); + } + else + throw new IllegalArgumentException("unsupported private key"); + } + + public String toString() + { + return "PrivateKeyEntry{key=" + + (key == null ? "-" : key.getClass().getName()) + "}"; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/Properties.java b/libjava/classpath/gnu/javax/crypto/keyring/Properties.java new file mode 100644 index 000000000..f25c82e36 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/Properties.java @@ -0,0 +1,203 @@ +/* Properties.java -- + Copyright (C) 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.crypto.keyring; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * A set of (name => value) pairs used in keyring entries. + * Keys and values are simple strings, with the key never being empty and always + * treated case-insensitively. + */ +public class Properties + implements Cloneable +{ + private HashMap props; + + /** + * Creates a new properties object. + */ + public Properties() + { + props = new HashMap(); + } + + /** + * Removes all properties from this object. + */ + public void clear() + { + props.clear(); + } + + /** + * Creates a copy of this properties object. + * + * @return The copy. + */ + public Object clone() + { + Properties result = new Properties(); + result.props.putAll(props); + return result; + } + + /** + * Tests if this object contains a given property name. + * + * @param key The key to test. + * @return True if this object contains the given key. + */ + public boolean containsKey(String key) + { + if (key == null || key.length() == 0) + return false; + return props.containsKey(canonicalize(key)); + } + + /** + * Tests if this object contains a given property value. + * + * @param value The value to test. + * @return True if this object contains the given value. + */ + public boolean containsValue(String value) + { + if (value == null) + return false; + return props.containsValue(value); + } + + /** + * Adds a new property to this object. + * + * @param key The key, which can neither be null nor empty. + * @param value The value, which cannot be null. + * @return The old value mapped by the key, if any. + * @throws IllegalArgumentException If either the key or value parameter is + * null, or if the key is empty. + */ + public String put(String key, String value) + { + if (key == null || value == null || key.length() == 0) + throw new IllegalArgumentException("key nor value can be null"); + return (String) props.put(canonicalize(key), value); + } + + /** + * Returns the value mapped by the given key, or null if there is no such + * mapping. + * + * @param key + */ + public String get(String key) + { + if (key == null || key.length() == 0) + return null; + return (String) props.get(canonicalize(key)); + } + + /** + * Removes a key and its value from this object. + * + * @param key The key of the property to remove. + * @return The old value mapped by the key, if any. + */ + public String remove(String key) + { + if (key == null || key.length() == 0) + return null; + return (String) props.remove(canonicalize(key)); + } + + /** + * Decodes a set of properties from the given input stream. + * + * @param in The input stream. + * @throws IOException If an I/O error occurs. + */ + public void decode(DataInputStream in) throws IOException + { + int len = in.readInt(); + MeteredInputStream min = new MeteredInputStream(in, len); + DataInputStream in2 = new DataInputStream(min); + while (! min.limitReached()) + { + String name = in2.readUTF(); + String value = in2.readUTF(); + put(name, value); + } + } + + /** + * Encodes this set of properties to the given output stream. + * + * @param out The output stream to encode to. + * @throws IOException If an I/O error occurs. + */ + public void encode(DataOutputStream out) throws IOException + { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + DataOutputStream out2 = new DataOutputStream(buf); + for (Iterator it = props.entrySet().iterator(); it.hasNext();) + { + Map.Entry entry = (Map.Entry) it.next(); + out2.writeUTF((String) entry.getKey()); + out2.writeUTF((String) entry.getValue()); + } + out.writeInt(buf.size()); + buf.writeTo(out); + } + + public String toString() + { + return props.toString(); + } + + private String canonicalize(String key) + { + return key.toLowerCase(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/PublicKeyEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/PublicKeyEntry.java new file mode 100644 index 000000000..837706d19 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/PublicKeyEntry.java @@ -0,0 +1,162 @@ +/* PublicKeyEntry.java -- + Copyright (C) 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.crypto.keyring; + +import gnu.java.security.key.IKeyPairCodec; +import gnu.java.security.key.KeyPairCodecFactory; +import gnu.java.security.key.dss.DSSPublicKey; +import gnu.java.security.key.rsa.GnuRSAPublicKey; +import gnu.javax.crypto.key.dh.GnuDHPublicKey; + +import java.io.DataInputStream; +import java.io.IOException; +import java.security.KeyFactory; +import java.security.PublicKey; +import java.security.spec.X509EncodedKeySpec; +import java.util.Date; + +public final class PublicKeyEntry + extends PrimitiveEntry +{ + public static final int TYPE = 6; + private PublicKey key; + + public PublicKeyEntry(PublicKey key, Date creationDate, Properties properties) + { + super(TYPE, creationDate, properties); + if (key == null) + throw new IllegalArgumentException("no key specified"); + this.key = key; + } + + private PublicKeyEntry() + { + super(TYPE); + } + + public static PublicKeyEntry decode(DataInputStream in) throws IOException + { + PublicKeyEntry entry = new PublicKeyEntry(); + entry.defaultDecode(in); + String type = entry.properties.get("type"); + if (type == null) + throw new MalformedKeyringException("no key type"); + if (type.equalsIgnoreCase("RAW-DSS")) + { + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dss"); + entry.key = coder.decodePublicKey(entry.payload); + } + else if (type.equalsIgnoreCase("RAW-RSA")) + { + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("rsa"); + entry.key = coder.decodePublicKey(entry.payload); + } + else if (type.equalsIgnoreCase("RAW-DH")) + { + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dh"); + entry.key = coder.decodePublicKey(entry.payload); + } + else if (type.equalsIgnoreCase("X.509")) + { + try + { + KeyFactory kf = KeyFactory.getInstance("RSA"); + entry.key = kf.generatePublic(new X509EncodedKeySpec(entry.payload)); + } + catch (Exception x) + { + } + if (entry.key == null) + { + try + { + KeyFactory kf = KeyFactory.getInstance("DSA"); + entry.key = kf.generatePublic(new X509EncodedKeySpec(entry.payload)); + } + catch (Exception x) + { + } + if (entry.key == null) + throw new MalformedKeyringException("could not decode X.509 key"); + } + } + else + throw new MalformedKeyringException("unsupported public key type: " + type); + return entry; + } + + /** + * Returns the public key. + * + * @return The public key. + */ + public PublicKey getKey() + { + return key; + } + + protected void encodePayload() throws IOException + { + if (key instanceof DSSPublicKey) + { + properties.put("type", "RAW-DSS"); + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dss"); + payload = coder.encodePublicKey(key); + } + else if (key instanceof GnuRSAPublicKey) + { + properties.put("type", "RAW-RSA"); + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("rsa"); + payload = coder.encodePublicKey(key); + } + else if (key instanceof GnuDHPublicKey) + { + properties.put("type", "RAW-DH"); + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dh"); + payload = coder.encodePublicKey(key); + } + else if (key.getFormat() != null && key.getFormat().equals("X.509")) + { + properties.put("type", "X.509"); + payload = key.getEncoded(); + } + else + throw new IllegalArgumentException("cannot encode public key"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/kwa/AESKeyWrap.java b/libjava/classpath/gnu/javax/crypto/kwa/AESKeyWrap.java new file mode 100644 index 000000000..bb86c5477 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/kwa/AESKeyWrap.java @@ -0,0 +1,168 @@ +/* AESWrap.java -- An implementation of RFC-3394 AES Key Wrap Algorithm + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.kwa; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.cipher.Rijndael; + +import java.security.InvalidKeyException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + * The GNU implementation of the AES Key Wrap Algorithm as described in [1]. + *

+ * References: + *

    + *
  1. .
  2. + *
  3. Advanced + * Encryption Standard (AES) Key Wrap Algorithm.
  4. + *
  5. XML Encryption Syntax and + * Processing.
  6. + *
+ */ +public class AESKeyWrap + extends BaseKeyWrappingAlgorithm +{ + private static final byte[] DEFAULT_IV = new byte[] { + (byte) 0xA6, (byte) 0xA6, (byte) 0xA6, (byte) 0xA6, + (byte) 0xA6, (byte) 0xA6, (byte) 0xA6, (byte) 0xA6 }; + + private Rijndael aes; + private byte[] iv; + + public AESKeyWrap() + { + super(Registry.AES_KWA); + + aes = new Rijndael(); + } + + protected void engineInit(Map attributes) throws InvalidKeyException + { + Map cipherAttributes = new HashMap(); + cipherAttributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(16)); + cipherAttributes.put(IBlockCipher.KEY_MATERIAL, + attributes.get(KEY_ENCRYPTION_KEY_MATERIAL)); + aes.reset(); + aes.init(cipherAttributes); + byte[] initialValue = (byte[]) attributes.get(INITIAL_VALUE); + iv = initialValue == null ? DEFAULT_IV : (byte[]) initialValue.clone(); + } + + protected byte[] engineWrap(byte[] in, int inOffset, int length) + { + // TODO: handle input length which is not a multiple of 8 as suggested by + // section 2.2.3.2 of RFC-3394 + if (length % 8 != 0) + throw new IllegalArgumentException("Input length MUST be a multiple of 8"); + int n = length / 8; + // output is always one block larger than input + byte[] result = new byte[length + 8]; + + // 1. init variables: we'll use out buffer for our work buffer; + // A will be the first block in out, while R will be the rest + System.arraycopy(iv, 0, result, 0, 8); + System.arraycopy(in, inOffset, result, 8, length); + byte[] B = new byte[2 * 8]; + // 2. compute intermediate values + long t; + for (int j = 0; j < 6; j++) + for (int i = 1; i <= n; i++) + { + System.arraycopy(result, 0, B, 0, 8); + System.arraycopy(result, i * 8, B, 8, 8); + aes.encryptBlock(B, 0, B, 0); + t = (n * j) + i; + result[0] = (byte)(B[0] ^ (t >>> 56)); + result[1] = (byte)(B[1] ^ (t >>> 48)); + result[2] = (byte)(B[2] ^ (t >>> 40)); + result[3] = (byte)(B[3] ^ (t >>> 32)); + result[4] = (byte)(B[4] ^ (t >>> 24)); + result[5] = (byte)(B[5] ^ (t >>> 16)); + result[6] = (byte)(B[6] ^ (t >>> 8)); + result[7] = (byte)(B[7] ^ t ); + System.arraycopy(B, 8, result, i * 8, 8); + } + return result; + } + + protected byte[] engineUnwrap(byte[] in, int inOffset, int length) + throws KeyUnwrappingException + { + // TODO: handle input length which is not a multiple of 8 as suggested by + // section 2.2.3.2 of RFC-3394 + if (length % 8 != 0) + throw new IllegalArgumentException("Input length MUST be a multiple of 8"); + // output is always one block shorter than input + byte[] result = new byte[length - 8]; + + // 1. init variables: we'll use out buffer for our R work buffer + byte[] A = new byte[8]; + System.arraycopy(in, inOffset, A, 0, 8); + System.arraycopy(in, inOffset + 8, result, 0, result.length); + byte[] B = new byte[2 * 8]; + // 2. compute intermediate values + int n = length / 8 - 1; + long t; + for (int j = 5; j >= 0; j--) + for (int i = n; i >= 1; i--) + { + t = (n * j) + i; + B[0] = (byte)(A[0] ^ (t >>> 56)); + B[1] = (byte)(A[1] ^ (t >>> 48)); + B[2] = (byte)(A[2] ^ (t >>> 40)); + B[3] = (byte)(A[3] ^ (t >>> 32)); + B[4] = (byte)(A[4] ^ (t >>> 24)); + B[5] = (byte)(A[5] ^ (t >>> 16)); + B[6] = (byte)(A[6] ^ (t >>> 8)); + B[7] = (byte)(A[7] ^ t ); + System.arraycopy(result, (i - 1) * 8, B, 8, 8); + aes.decryptBlock(B, 0, B, 0); + System.arraycopy(B, 0, A, 0, 8); + System.arraycopy(B, 8, result, (i - 1) * 8, 8); + } + if (! Arrays.equals(A, iv)) + throw new KeyUnwrappingException(); + + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/kwa/BaseKeyWrappingAlgorithm.java b/libjava/classpath/gnu/javax/crypto/kwa/BaseKeyWrappingAlgorithm.java new file mode 100644 index 000000000..80b114a02 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/kwa/BaseKeyWrappingAlgorithm.java @@ -0,0 +1,145 @@ +/* BaseKeyWrappingAlgorithm.java -- FIXME: briefly describe file purpose + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.kwa; + +import gnu.java.security.util.PRNG; + +import java.security.InvalidKeyException; +import java.util.Collections; +import java.util.Map; + +import javax.crypto.ShortBufferException; + +/** + * A base class to facilitate implementation of concrete Key Wrapping + * Algorithms. + */ +public abstract class BaseKeyWrappingAlgorithm + implements IKeyWrappingAlgorithm +{ + /** The canonical name of the key wrapping algorithm. */ + protected String name; + /** A source of randomness if/when needed by concrete implementations. */ + private PRNG prng; + + /** + * Protected constructor. + * + * @param name the key wrapping algorithm canonical name. + */ + protected BaseKeyWrappingAlgorithm(String name) + { + super(); + } + + public String name() + { + return this.name; + } + + public void init(Map attributes) throws InvalidKeyException + { + if (attributes == null) + attributes = Collections.EMPTY_MAP; + + engineInit(attributes); + } + + public int wrap(byte[] in, int inOffset, int length, byte[] out, int outOffset) + throws ShortBufferException + { + if (outOffset < 0) + throw new IllegalArgumentException("Output offset MUST NOT be negative"); + byte[] result = wrap(in, inOffset, length); + if (outOffset + result.length > out.length) + throw new ShortBufferException(); + System.arraycopy(result, 0, out, outOffset, result.length); + return result.length; + } + + public byte[] wrap(byte[] in, int inOffset, int length) + { + if (inOffset < 0) + throw new IllegalArgumentException("Input offset MUST NOT be negative"); + if (length < 0) + throw new IllegalArgumentException("Input length MUST NOT be negative"); + + return engineWrap(in, inOffset, length); + } + + public int unwrap(byte[] in, int inOffset, int length, + byte[] out, int outOffset) + throws ShortBufferException, KeyUnwrappingException + { + if (outOffset < 0) + throw new IllegalArgumentException("Output offset MUST NOT be negative"); + byte[] result = engineUnwrap(in, inOffset, length); + if (outOffset + result.length > out.length) + throw new ShortBufferException(); + System.arraycopy(result, 0, out, outOffset, result.length); + return result.length; + } + + public byte[] unwrap(byte[] in, int inOffset, int length) + throws KeyUnwrappingException + { + if (inOffset < 0) + throw new IllegalArgumentException("Input offset MUST NOT be negative"); + if (length < 0) + throw new IllegalArgumentException("Input length MUST NOT be negative"); + + return engineUnwrap(in, inOffset, length); + } + + protected abstract void engineInit(Map attributes) throws InvalidKeyException; + + protected abstract byte[] engineWrap(byte[] in, int inOffset, int length); + + protected abstract byte[] engineUnwrap(byte[] in, int inOffset, int length) + throws KeyUnwrappingException; + + /** @return a strong pseudo-random number generator if/when needed. */ + protected PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + + return prng; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/kwa/IKeyWrappingAlgorithm.java b/libjava/classpath/gnu/javax/crypto/kwa/IKeyWrappingAlgorithm.java new file mode 100644 index 000000000..271ec5c1b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/kwa/IKeyWrappingAlgorithm.java @@ -0,0 +1,160 @@ +/* IKeyWrappingAlgorithm.java -- FIXME: briefly describe file purpose + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.kwa; + +import java.security.InvalidKeyException; +import java.security.SecureRandom; +import java.util.Map; + +import javax.crypto.ShortBufferException; + +/** + * Constants and visible methods available to all GNU Key Wrapping Algorithm + * implementations. + */ +public interface IKeyWrappingAlgorithm +{ + /** + * Name of the property, in the attributes map, that references the Key + * Wrapping Algorithm KEK (Key Encryption Key) material. The object referenced + * by this property is a byte array containing the keying material for the + * underlying block cipher. + */ + String KEY_ENCRYPTION_KEY_MATERIAL = "gnu.crypto.kwa.kek"; + /** + * Name of the property, in the attributes map, that references the Initial + * Value (IV) material. The object referenced by this property is a byte array + * containing the initial integrity check register value. + */ + String INITIAL_VALUE = "gnu.crypto.kwa.iv"; + /** + * Property name of an optional {@link SecureRandom} instance to use. The + * default is to use a {@link gnu.java.security.util.PRNG} instance. + */ + String SOURCE_OF_RANDOMNESS = "gnu.crypto.kwa.prng"; + + /** + * Returns the canonical name of this Key Wrapping Algorithm. + * + * @return the canonical name of this Key Wrapping Algorithm. + */ + String name(); + + /** + * Initializes this instance with the designated algorithm specific + * attributes. + * + * @param attributes a map of name-to-value pairs the Key Wrapping Algorithm + * must use for its setup. + * @throws InvalidKeyException if an exception is encountered while seting up + * the Key Wrapping Algorithm keying material (KEK). + */ + void init(Map attributes) throws InvalidKeyException; + + /** + * Wraps the designated plain text bytes. + * + * @param in the input byte array containing the plain text. + * @param inOffset the offset into in where the first byte of + * the plain text (key material) to wrap is located. + * @param length the number of bytes to wrap. + * @param out the output byte array where the wrapped key material will be + * stored. + * @param outOffset the offset into out of the first wrapped + * byte. + * @return the number of bytes of the wrapped key material; i.e. the length, + * in out, starting from outOffset + * where the cipher text (wrapped key material) are stored. + * @throws ShortBufferException if the output buffer is not long enough to + * accomodate the number of bytes resulting from wrapping the plain + * text. + */ + int wrap(byte[] in, int inOffset, int length, byte[] out, int outOffset) + throws ShortBufferException; + + /** + * Wraps the designated plain text bytes. + * + * @param in the input byte array containing the plain text. + * @param inOffset the offset into in where the first byte of + * the plain text (key material) to wrap is located. + * @param length the number of bytes to wrap. + * @return a newly allocated byte array containing the cipher text. + */ + byte[] wrap(byte[] in, int inOffset, int length); + + /** + * Unwraps the designated cipher text bytes. + * + * @param in the input byte array containing the cipher text. + * @param inOffset the offset into in where the first byte of + * the cipher text (already wrapped key material) to unwrap is + * located. + * @param length the number of bytes to unwrap. + * @param out the output byte array where the unwrapped key material will be + * stored. + * @param outOffset the offset into out of the first unwrapped + * byte. + * @return the number of bytes of the unwrapped key material; i.e. the length, + * in out, starting from outOffset + * where the plain text (unwrapped key material) are stored. + * @throws ShortBufferException if the output buffer is not long enough to + * accomodate the number of bytes resulting from unwrapping the + * cipher text. + * @throws KeyUnwrappingException if after unwrapping the cipher text, the + * bytes at the begining did not match the initial value. + */ + int unwrap(byte[] in, int inOffset, int length, byte[] out, int outOffset) + throws ShortBufferException, KeyUnwrappingException; + + /** + * Unwraps the designated cipher text bytes. + * + * @param in the input byte array containing the cipher text. + * @param inOffset the offset into in where the first byte of + * the cipher text (already wrapped key material) to unwrap is + * located. + * @param length the number of bytes to unwrap. + * @return a newly allocated byte array containing the plain text. + * @throws KeyUnwrappingException if after unwrapping the cipher text, the + * bytes at the begining did not match the initial value. + */ + byte[] unwrap(byte[] in, int inOffset, int length) + throws KeyUnwrappingException; +} diff --git a/libjava/classpath/gnu/javax/crypto/kwa/KeyUnwrappingException.java b/libjava/classpath/gnu/javax/crypto/kwa/KeyUnwrappingException.java new file mode 100644 index 000000000..54b4aff0a --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/kwa/KeyUnwrappingException.java @@ -0,0 +1,67 @@ +/* KeyUnwrappingException.java -- FIXME: briefly describe file purpose + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.kwa; + +import java.security.GeneralSecurityException; + +/** + * A checked security exception to denote an unexpected problem while unwrapping + * key material with a Key Wrapping Algorithm. + */ +public class KeyUnwrappingException + extends GeneralSecurityException +{ + /** + * Create a new instance with no descriptive error message. + */ + public KeyUnwrappingException() + { + super(); + } + + /** + * Create a new instance with a descriptive error message. + * + * @param msg the descriptive error message + */ + public KeyUnwrappingException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/kwa/KeyWrappingAlgorithmFactory.java b/libjava/classpath/gnu/javax/crypto/kwa/KeyWrappingAlgorithmFactory.java new file mode 100644 index 000000000..abd208c07 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/kwa/KeyWrappingAlgorithmFactory.java @@ -0,0 +1,110 @@ +/* KeyWrappingAlgorithmFactory.java -- FIXME: briefly describe file purpose + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.kwa; + +import gnu.java.security.Registry; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * A Factory class for the Key Wrapping Algorithm implementations. + */ +public class KeyWrappingAlgorithmFactory +{ + /** Names of Key Wrapping Algorihms cached for speed. */ + private static Set names; + + /** Trivial constructor to enforce Singleton pattern. */ + private KeyWrappingAlgorithmFactory() + { + super(); + } + + /** + * Returns an instance of a key-wrapping algorithm given its name. + * + * @param name the case-insensitive name of the key-wrapping algorithm. + * @return an instance of the designated key-wrapping algorithm, or + * null if none was found. + * @exception InternalError if the implementation does not pass its self-test. + */ + public static final IKeyWrappingAlgorithm getInstance(String name) + { + if (name == null) + return null; + name = name.trim(); + IKeyWrappingAlgorithm result = null; + if (name.equalsIgnoreCase(Registry.AES_KWA) + || name.equalsIgnoreCase(Registry.AES128_KWA) + || name.equalsIgnoreCase(Registry.AES192_KWA) + || name.equalsIgnoreCase(Registry.AES256_KWA) + || name.equalsIgnoreCase(Registry.RIJNDAEL_KWA)) + result = new AESKeyWrap(); + else if (name.equalsIgnoreCase(Registry.TRIPLEDES_KWA) + || name.equalsIgnoreCase(Registry.DESEDE_KWA)) + result = new TripleDESKeyWrap(); + + return result; + } + + /** + * Returns a {@link Set} of key wrapping algorithm names supported by this + * Factory. + * + * @return a {@link Set} of key wrapping algorithm names (Strings). + */ + public static synchronized final Set getNames() + { + if (names == null) + { + HashSet hs = new HashSet(); + hs.add(Registry.AES_KWA); + hs.add(Registry.AES128_KWA); + hs.add(Registry.AES192_KWA); + hs.add(Registry.AES256_KWA); + hs.add(Registry.RIJNDAEL_KWA); + hs.add(Registry.TRIPLEDES_KWA); + hs.add(Registry.DESEDE_KWA); + names = Collections.unmodifiableSet(hs); + } + return names; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/kwa/TripleDESKeyWrap.java b/libjava/classpath/gnu/javax/crypto/kwa/TripleDESKeyWrap.java new file mode 100644 index 000000000..28b16cf31 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/kwa/TripleDESKeyWrap.java @@ -0,0 +1,292 @@ +/* TripleDESKeyWrap.java -- FIXME: briefly describe file purpose + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.kwa; + +import gnu.java.security.Registry; +import gnu.java.security.hash.Sha160; +import gnu.javax.crypto.assembly.Assembly; +import gnu.javax.crypto.assembly.Cascade; +import gnu.javax.crypto.assembly.Direction; +import gnu.javax.crypto.assembly.Stage; +import gnu.javax.crypto.assembly.Transformer; +import gnu.javax.crypto.assembly.TransformerException; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.cipher.TripleDES; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.mode.ModeFactory; + +import java.security.InvalidKeyException; +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + * The GNU implementation of the Triple DES Key Wrap Algorithm as described in + * [1]. + *

+ * IMPORTANT: This class is NOT thread safe. + *

+ * References: + *

    + *
  1. Triple-DES and + * RC2 Key Wrapping.
  2. + *
  3. XML Encryption Syntax and + * Processing.
  4. + *
+ */ +public class TripleDESKeyWrap + extends BaseKeyWrappingAlgorithm +{ + private static final byte[] DEFAULT_IV = new byte[] { + (byte) 0x4A, (byte) 0xDD, (byte) 0xA2, (byte) 0x2C, + (byte) 0x79, (byte) 0xE8, (byte) 0x21, (byte) 0x05 }; + + private Assembly asm; + private HashMap asmAttributes = new HashMap(); + private HashMap modeAttributes = new HashMap(); + private Sha160 sha = new Sha160(); + private SecureRandom rnd; + + public TripleDESKeyWrap() + { + super(Registry.TRIPLEDES_KWA); + } + + protected void engineInit(Map attributes) throws InvalidKeyException + { + rnd = (SecureRandom) attributes.get(IKeyWrappingAlgorithm.SOURCE_OF_RANDOMNESS); + IMode des3CBC = ModeFactory.getInstance(Registry.CBC_MODE, new TripleDES(), 8); + Stage des3CBCStage = Stage.getInstance(des3CBC, Direction.FORWARD); + Cascade cascade = new Cascade(); + Object modeNdx = cascade.append(des3CBCStage); + + asmAttributes.put(modeNdx, modeAttributes); + + asm = new Assembly(); + asm.addPreTransformer(Transformer.getCascadeTransformer(cascade)); + + modeAttributes.put(IBlockCipher.KEY_MATERIAL, + attributes.get(KEY_ENCRYPTION_KEY_MATERIAL)); + asmAttributes.put(Assembly.DIRECTION, Direction.FORWARD); + } + + protected byte[] engineWrap(byte[] in, int inOffset, int length) + { + // The same key wrap algorithm is used for both Two-key Triple-DES and + // Three-key Triple-DES keys. When a Two-key Triple-DES key is to be + // wrapped, a third DES key with the same value as the first DES key is + // created. Thus, all wrapped Triple-DES keys include three DES keys. + if (length != 16 && length != 24) + throw new IllegalArgumentException("Only 2- and 3-key Triple DES keys are alowed"); + + byte[] CEK = new byte[24]; + if (length == 16) + { + System.arraycopy(in, inOffset, CEK, 0, 16); + System.arraycopy(in, inOffset, CEK, 16, 8); + } + else + System.arraycopy(in, inOffset, CEK, 0, 24); + + // TODO: check for the following: + // However, a Two-key Triple-DES key MUST NOT be used to wrap a Three- + // key Triple-DES key that is comprised of three unique DES keys. + + // 1. Set odd parity for each of the DES key octets comprising the + // Three-Key Triple-DES key that is to be wrapped, call the result + // CEK. + TripleDES.adjustParity(CEK, 0); + + // 2. Compute an 8 octet key checksum value on CEK as described above in + // Section 2, call the result ICV. + sha.update(CEK); + byte[] hash = sha.digest(); + byte[] ICV = new byte[8]; + System.arraycopy(hash, 0, ICV, 0, 8); + + // 3. Let CEKICV = CEK || ICV. + byte[] CEKICV = new byte[CEK.length + ICV.length]; + System.arraycopy(CEK, 0, CEKICV, 0, CEK.length); + System.arraycopy(ICV, 0, CEKICV, CEK.length, ICV.length); + + // 4. Generate 8 octets at random, call the result IV. + byte[] IV = new byte[8]; + nextRandomBytes(IV); + + // 5. Encrypt CEKICV in CBC mode using the key-encryption key. Use the + // random value generated in the previous step as the initialization + // vector (IV). Call the ciphertext TEMP1. + modeAttributes.put(IMode.IV, IV); + asmAttributes.put(Assembly.DIRECTION, Direction.FORWARD); + byte[] TEMP1; + try + { + asm.init(asmAttributes); + TEMP1 = asm.lastUpdate(CEKICV); + } + catch (TransformerException x) + { + throw new RuntimeException(x); + } + + // 6. Let TEMP2 = IV || TEMP1. + byte[] TEMP2 = new byte[IV.length + TEMP1.length]; + System.arraycopy(IV, 0, TEMP2, 0, IV.length); + System.arraycopy(TEMP1, 0, TEMP2, IV.length, TEMP1.length); + + // 7. Reverse the order of the octets in TEMP2. That is, the most + // significant (first) octet is swapped with the least significant + // (last) octet, and so on. Call the result TEMP3. + byte[] TEMP3 = new byte[TEMP2.length]; + for (int i = 0, j = TEMP2.length - 1; i < TEMP2.length; i++, j--) + TEMP3[j] = TEMP2[i]; + + // 8. Encrypt TEMP3 in CBC mode using the key-encryption key. Use an + // initialization vector (IV) of 0x4adda22c79e82105. The ciphertext + // is 40 octets long. + modeAttributes.put(IMode.IV, DEFAULT_IV); + asmAttributes.put(Assembly.DIRECTION, Direction.FORWARD); + byte[] result; + try + { + asm.init(asmAttributes); + result = asm.lastUpdate(TEMP3); + } + catch (TransformerException x) + { + throw new RuntimeException(x); + } + return result; + } + + protected byte[] engineUnwrap(byte[] in, int inOffset, int length) + throws KeyUnwrappingException + { + // 1. If the wrapped key is not 40 octets, then error. + if (length != 40) + throw new IllegalArgumentException("length MUST be 40"); + + // 2. Decrypt the wrapped key in CBC mode using the key-encryption key. + // Use an initialization vector (IV) of 0x4adda22c79e82105. Call the + // output TEMP3. + modeAttributes.put(IMode.IV, DEFAULT_IV); + asmAttributes.put(Assembly.DIRECTION, Direction.REVERSED); + byte[] TEMP3; + try + { + asm.init(asmAttributes); + TEMP3 = asm.lastUpdate(in, inOffset, 40); + } + catch (TransformerException x) + { + throw new RuntimeException(x); + } + + // 3. Reverse the order of the octets in TEMP3. That is, the most + // significant (first) octet is swapped with the least significant + // (last) octet, and so on. Call the result TEMP2. + byte[] TEMP2 = new byte[40]; + for (int i = 0, j = 40 - 1; i < 40; i++, j--) + TEMP2[j] = TEMP3[i]; + + // 4. Decompose TEMP2 into IV and TEMP1. IV is the most significant + // (first) 8 octets, and TEMP1 is the least significant (last) 32 + // octets. + byte[] IV = new byte[8]; + byte[] TEMP1 = new byte[32]; + System.arraycopy(TEMP2, 0, IV, 0, 8); + System.arraycopy(TEMP2, 8, TEMP1, 0, 32); + + // 5. Decrypt TEMP1 in CBC mode using the key-encryption key. Use the + // IV value from the previous step as the initialization vector. + // Call the ciphertext CEKICV. + modeAttributes.put(IMode.IV, IV); + asmAttributes.put(Assembly.DIRECTION, Direction.REVERSED); + byte[] CEKICV; + try + { + asm.init(asmAttributes); + CEKICV = asm.lastUpdate(TEMP1, 0, 32); + } + catch (TransformerException x) + { + throw new RuntimeException(x); + } + + // 6. Decompose CEKICV into CEK and ICV. CEK is the most significant + // (first) 24 octets, and ICV is the least significant (last) 8 + // octets. + byte[] CEK = new byte[24]; + byte[] ICV = new byte[8]; + System.arraycopy(CEKICV, 0, CEK, 0, 24); + System.arraycopy(CEKICV, 24, ICV, 0, 8); + + // 7. Compute an 8 octet key checksum value on CEK as described above in + // Section 2. If the computed key checksum value does not match the + // decrypted key checksum value, ICV, then error. + sha.update(CEK); + byte[] hash = sha.digest(); + byte[] computedICV = new byte[8]; + System.arraycopy(hash, 0, computedICV, 0, 8); + if (! Arrays.equals(ICV, computedICV)) + throw new KeyUnwrappingException("ICV and computed ICV MUST match"); + + // 8. Check for odd parity each of the DES key octets comprising CEK. + // If parity is incorrect, then error. + if (! TripleDES.isParityAdjusted(CEK, 0)) + throw new KeyUnwrappingException("Triple-DES key parity MUST be adjusted"); + + // 9. Use CEK as a Triple-DES key. + return CEK; + } + + /** + * Fills the designated byte array with random data. + * + * @param buffer the byte array to fill with random data. + */ + private void nextRandomBytes(byte[] buffer) + { + if (rnd != null) + rnd.nextBytes(buffer); + else + getDefaultPRNG().nextBytes(buffer); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/BaseMac.java b/libjava/classpath/gnu/javax/crypto/mac/BaseMac.java new file mode 100644 index 000000000..4c524e905 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/BaseMac.java @@ -0,0 +1,127 @@ +/* BaseMac.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.mac; + +import gnu.java.security.hash.IMessageDigest; + +import java.security.InvalidKeyException; +import java.util.Map; + +/** + * A base abstract class to facilitate MAC (Message Authentication Code) + * implementations. + */ +public abstract class BaseMac + implements IMac +{ + /** The canonical name prefix of the MAC. */ + protected String name; + /** Reference to the underlying hash algorithm instance. */ + protected IMessageDigest underlyingHash; + /** The length of the truncated output in bytes. */ + protected int truncatedSize; + + /** + * Trivial constructor for use by concrete subclasses. + * + * @param name the canonical name of this instance. + */ + protected BaseMac(String name) + { + super(); + + this.name = name; + } + + /** + * Trivial constructor for use by concrete subclasses. + * + * @param name the canonical name of this instance. + * @param underlyingHash the underlying message digest algorithm instance. + */ + protected BaseMac(String name, IMessageDigest underlyingHash) + { + this(name); + + if (underlyingHash != null) + truncatedSize = underlyingHash.hashSize(); + this.underlyingHash = underlyingHash; + } + + public String name() + { + return name; + } + + public int macSize() + { + return truncatedSize; + } + + public void update(byte b) + { + underlyingHash.update(b); + } + + public void update(byte[] b, int offset, int len) + { + underlyingHash.update(b, offset, len); + } + + public void reset() + { + underlyingHash.reset(); + } + + public Object clone() throws CloneNotSupportedException + { + BaseMac result = (BaseMac) super.clone(); + if (this.underlyingHash != null) + result.underlyingHash = (IMessageDigest) this.underlyingHash.clone(); + + return result; + } + + public abstract void init(Map attributes) throws InvalidKeyException, + IllegalStateException; + + public abstract byte[] digest(); + + public abstract boolean selfTest(); +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/HMac.java b/libjava/classpath/gnu/javax/crypto/mac/HMac.java new file mode 100644 index 000000000..ae2cd3ce2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/HMac.java @@ -0,0 +1,263 @@ +/* HMac.java -- + 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.crypto.mac; + +import gnu.java.security.Registry; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.hash.MD5; +import gnu.java.security.util.Util; + +import java.security.InvalidKeyException; +import java.util.HashMap; +import java.util.Map; + +/** + * The implementation of the HMAC (Keyed-Hash Message Authentication + * Code). + *

+ * HMAC can be used in combination with any iterated cryptographic hash + * function. HMAC also uses a secret key for calculation and + * verification of the message authentication values. The main goals behind this + * construction are: + *

+ *

+ * References: + *

    + *
  1. RFC 2104HMAC: + * Keyed-Hashing for Message Authentication.
    + * H. Krawczyk, M. Bellare, and R. Canetti.
  2. + *
+ */ +public class HMac + extends BaseMac + implements Cloneable +{ + public static final String USE_WITH_PKCS5_V2 = "gnu.crypto.hmac.pkcs5"; + private static final byte IPAD_BYTE = 0x36; + private static final byte OPAD_BYTE = 0x5C; + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + protected int macSize; + protected int blockSize; + protected IMessageDigest ipadHash; + protected IMessageDigest opadHash; + protected byte[] ipad; + + /** + * Trivial constructor for use by concrete subclasses. + * + * @param underlyingHash the underlying hash algorithm instance. + */ + protected HMac(IMessageDigest underlyingHash) + { + super(Registry.HMAC_NAME_PREFIX + underlyingHash.name(), underlyingHash); + + this.blockSize = underlyingHash.blockSize(); + this.macSize = underlyingHash.hashSize(); + ipadHash = opadHash = null; + } + + public Object clone() throws CloneNotSupportedException + { + HMac result = (HMac) super.clone(); + if (this.ipadHash != null) + result.ipadHash = (IMessageDigest) this.ipadHash.clone(); + if (this.opadHash != null) + result.opadHash = (IMessageDigest) this.opadHash.clone(); + if (this.ipad != null) + result.ipad = (byte[]) this.ipad.clone(); + + return result; + } + + public void init(Map attributes) throws InvalidKeyException, + IllegalStateException + { + Integer ts = (Integer) attributes.get(TRUNCATED_SIZE); + truncatedSize = (ts == null ? macSize : ts.intValue()); + if (truncatedSize < (macSize / 2)) + throw new IllegalArgumentException("Truncated size too small"); + else if (truncatedSize < 10) + throw new IllegalArgumentException("Truncated size less than 80 bits"); + + // we dont use/save the key outside this method + byte[] K = (byte[]) attributes.get(MAC_KEY_MATERIAL); + if (K == null) + { // take it as an indication to re-use previous key if set + if (ipadHash == null) + throw new InvalidKeyException("Null key"); + // we already went through the motions; ie. up to step #4. re-use + underlyingHash = (IMessageDigest) ipadHash.clone(); + return; + } + + // for HMACs used in key-derivation functions (e.g. PBKDF2) the key material + // need not be >= the (output) block size of the underlying algorithm + Boolean pkcs5 = (Boolean) attributes.get(USE_WITH_PKCS5_V2); + if (pkcs5 == null) + pkcs5 = Boolean.FALSE; + if (K.length < macSize && ! pkcs5.booleanValue()) + throw new InvalidKeyException("Key too short"); + + if (K.length > blockSize) + { + // (0) replace K with HASH(K) if K is larger than the hash's block size. + // Then pad with zeros until it is the correct size (the next `if'). + underlyingHash.update(K, 0, K.length); + K = underlyingHash.digest(); + } + if (K.length < blockSize) + { + // (1) append zeros to the end of K to create a B byte string (e.g., if + // K is of length 20 bytes and B=64, then K will be appended with 44 + // zero bytes 0x00) + int limit = (K.length > blockSize) ? blockSize : K.length; + byte[] newK = new byte[blockSize]; + System.arraycopy(K, 0, newK, 0, limit); + K = newK; + } + underlyingHash.reset(); + opadHash = (IMessageDigest) underlyingHash.clone(); + if (ipad == null) + ipad = new byte[blockSize]; + // (2) XOR (bitwise exclusive-OR) the B byte string computed in step (1) + // with ipad + // (3) append the stream of data 'text' to the B byte string resulting from + // step (2) + // (4) apply H to the stream generated in step (3) + for (int i = 0; i < blockSize; i++) + ipad[i] = (byte)(K[i] ^ IPAD_BYTE); + for (int i = 0; i < blockSize; i++) + opadHash.update((byte)(K[i] ^ OPAD_BYTE)); + underlyingHash.update(ipad, 0, blockSize); + ipadHash = (IMessageDigest) underlyingHash.clone(); + K = null; + } + + public void reset() + { + super.reset(); + if (ipad != null) + { + underlyingHash.update(ipad, 0, blockSize); + ipadHash = (IMessageDigest) underlyingHash.clone(); + } + } + + public byte[] digest() + { + if (ipadHash == null) + throw new IllegalStateException("HMAC not initialised"); + byte[] out = underlyingHash.digest(); + // (5) XOR (bitwise exclusive-OR) the B byte string computed in step (1) + // with opad + underlyingHash = (IMessageDigest) opadHash.clone(); + // (6) append the H result from step (4) to the B byte string resulting from + // step (5) + underlyingHash.update(out, 0, macSize); + // (7) apply H to the stream generated in step (6) and output the result + out = underlyingHash.digest(); // which also resets the underlying hash + // truncate and return + if (truncatedSize == macSize) + return out; + byte[] result = new byte[truncatedSize]; + System.arraycopy(out, 0, result, 0, truncatedSize); + return result; + } + + public boolean selfTest() + { + if (valid == null) + { + try + { + IMac mac = new HMac(new MD5()); // use rfc-2104 test vectors + String tv1 = "9294727A3638BB1C13F48EF8158BFC9D"; + String tv3 = "56BE34521D144C88DBB8C733F0E8B3F6"; + byte[] k1 = new byte[] { + 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, + 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B }; + byte[] k3 = new byte[] { + (byte) 0xAA, (byte) 0xAA, (byte) 0xAA, (byte) 0xAA, + (byte) 0xAA, (byte) 0xAA, (byte) 0xAA, (byte) 0xAA, + (byte) 0xAA, (byte) 0xAA, (byte) 0xAA, (byte) 0xAA, + (byte) 0xAA, (byte) 0xAA, (byte) 0xAA, (byte) 0xAA }; + byte[] data = new byte[50]; + for (int i = 0; i < 50;) + data[i++] = (byte) 0xDD; + + HashMap map = new HashMap(); + // test vector #1 + map.put(MAC_KEY_MATERIAL, k1); + mac.init(map); + mac.update("Hi There".getBytes("ASCII"), 0, 8); + if (! tv1.equals(Util.toString(mac.digest()))) + valid = Boolean.FALSE; + + // test #2 is not used since it causes a "Key too short" exception + + // test vector #3 + map.put(MAC_KEY_MATERIAL, k3); + mac.init(map); + mac.update(data, 0, 50); + if (! tv3.equals(Util.toString(mac.digest()))) + valid = Boolean.FALSE; + valid = Boolean.TRUE; + } + catch (Exception x) + { + x.printStackTrace(System.err); + valid = Boolean.FALSE; + } + } + return valid.booleanValue(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/HMacFactory.java b/libjava/classpath/gnu/javax/crypto/mac/HMacFactory.java new file mode 100644 index 000000000..0afd8c6ac --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/HMacFactory.java @@ -0,0 +1,111 @@ +/* HMacFactory.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.mac; + +import gnu.java.security.Registry; +import gnu.java.security.hash.HashFactory; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +/** + * A Factory to instantiate Keyed-Hash Message Authentication Code + * (HMAC) algorithm instances. + */ +public class HMacFactory + implements Registry +{ + /** Trivial constructor to enforce Singleton pattern. */ + private HMacFactory() + { + super(); + } + + /** + * Return an instance of a HMAC algorithm given the name of its + * underlying hash function, prefixed with the literal defined in + * {@link Registry#HMAC_NAME_PREFIX}. + * + * @param name the fully qualified name of the underlying algorithm: composed + * as the concatenation of a literal prefix (see + * {@link Registry#HMAC_NAME_PREFIX}) and the name of the underlying + * hash algorithm. + * @return an instance of the HMAC algorithm, or null + * if none can be constructed. + * @exception InternalError if the implementation does not pass its self-test. + */ + public static IMac getInstance(String name) + { + if (name == null) + return null; + + name = name.trim(); + name = name.toLowerCase(); + if (! name.startsWith(HMAC_NAME_PREFIX)) + return null; + + // strip the prefix + name = name.substring(HMAC_NAME_PREFIX.length()).trim(); + IMac result = new HMac(HashFactory.getInstance(name)); + if (result != null && ! result.selfTest()) + throw new InternalError(result.name()); + + return result; + } + + /** + *

+ * Returns a {@link java.util.Set} of names of HMAC algorithms + * supported by this Factory. + *

+ * + * @return a {@link java.util.Set} of HMAC algorithm names (Strings). + */ + public static final Set getNames() + { + Set hashNames = HashFactory.getNames(); + HashSet hs = new HashSet(); + for (Iterator it = hashNames.iterator(); it.hasNext();) + hs.add(HMAC_NAME_PREFIX + ((String) it.next())); + + return Collections.unmodifiableSet(hs); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/IMac.java b/libjava/classpath/gnu/javax/crypto/mac/IMac.java new file mode 100644 index 000000000..a9582564d --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/IMac.java @@ -0,0 +1,181 @@ +/* IMac.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.mac; + +import java.security.InvalidKeyException; +import java.util.Map; + +/** + * The basic visible methods of any MAC (Message Authentication Code) algorithm. + *

+ * A MAC provides a way to check the integrity of information + * transmitted over, or stored in, an unreliable medium, based on a secret key. + * Typically, MACs are used between two parties, that share a common + * secret key, in order to validate information transmitted between them. + *

+ * When a MAC algorithm is based on a cryptographic hash function, it is + * then called to a HMAC (Hashed Message Authentication Code) --see RFC-2104. + *

+ * Another type of MAC algorithms exist: UMAC or Universal Message + * Authentication Code, described in + * draft-krovetz-umac-01.txt. + *

+ * With UMACs, the sender and receiver share a common secret key (the + * MAC key) which determines: + *

+ *

+ * References: + *

    + *
  1. RFC 2104HMAC: + * Keyed-Hashing for Message Authentication.
    + * H. Krawczyk, M. Bellare, and R. Canetti.
  2. + *
  3. + * UMAC: Message Authentication Code using Universal Hashing.
    + * T. Krovetz, J. Black, S. Halevi, A. Hevia, H. Krawczyk, and P. Rogaway.
  4. + *
+ */ +public interface IMac +{ + /** + * Property name of the user-supplied key material. The value associated to + * this property name is taken to be a byte array. + */ + String MAC_KEY_MATERIAL = "gnu.crypto.mac.key.material"; + /** + * Property name of the desired truncated output size in bytes. The value + * associated to this property name is taken to be an integer. If no value is + * specified in the attributes map at initialisation time, then all bytes of + * the underlying hash algorithm's output are emitted. + *

+ * This implementation, follows the recommendation of the RFC 2104 + * authors; specifically: + *

+   *     We recommend that the output length t be not less than half the
+   *     length of the hash output (to match the birthday attack bound)
+   *     and not less than 80 bits (a suitable lower bound on the number
+   *     of bits that need to be predicted by an attacker).
+   * 
+ */ + String TRUNCATED_SIZE = "gnu.crypto.mac.truncated.size"; + + /** + * Returns the canonical name of this algorithm. + * + * @return the canonical name of this algorithm. + */ + String name(); + + /** + * Returns the output length in bytes of this MAC algorithm. + * + * @return the output length in bytes of this MAC algorithm. + */ + int macSize(); + + /** + * Initialises the algorithm with designated attributes. Permissible names and + * values are described in the class documentation above. + * + * @param attributes a set of name-value pairs that describe the desired + * future instance behaviour. + * @exception InvalidKeyException if the key data is invalid. + * @exception IllegalStateException if the instance is already initialised. + * @see #MAC_KEY_MATERIAL + */ + void init(Map attributes) throws InvalidKeyException, IllegalStateException; + + /** + * Continues a MAC operation using the input byte. + * + * @param b the input byte to digest. + */ + void update(byte b); + + /** + * Continues a MAC operation, by filling the buffer, processing data + * in the algorithm's MAC_SIZE-bit block(s), updating the context and count, + * and buffering the remaining bytes in buffer for the next operation. + * + * @param in the input block. + * @param offset start of meaningful bytes in input block. + * @param length number of bytes, in input block, to consider. + */ + void update(byte[] in, int offset, int length); + + /** + * Completes the MAC by performing final operations such as padding + * and resetting the instance. + * + * @return the array of bytes representing the MAC value. + */ + byte[] digest(); + + /** + * Resets the algorithm instance for re-initialisation and use with other + * characteristics. This method always succeeds. + */ + void reset(); + + /** + * A basic test. Ensures that the MAC of a pre-determined message is equal to + * a known pre-computed value. + * + * @return true if the implementation passes a basic self-test. + * Returns false otherwise. + */ + boolean selfTest(); + + /** + * Returns a clone copy of this instance. + * + * @return a clone copy of this instance. + */ + Object clone() throws CloneNotSupportedException; +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/MacFactory.java b/libjava/classpath/gnu/javax/crypto/mac/MacFactory.java new file mode 100644 index 000000000..5e3b50f7f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/MacFactory.java @@ -0,0 +1,130 @@ +/* MacFactory.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.mac; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +/** + * A Factory that instantiates instances of every supported Message + * Authentication Code algorithms, including all HMAC algorithms. + */ +public class MacFactory + implements Registry +{ + private static Set names; + + /** Trivial constructor to enforce Singleton pattern. */ + private MacFactory() + { + super(); + } + + /** + * Returns an instance of a MAC algorithm given its name. + * + * @param name the name of the MAC algorithm. + * @return an instance of the MAC algorithm, or null if + * none can be constructed. + * @exception InternalError if the implementation does not pass its self-test. + */ + public static IMac getInstance(String name) + { + if (name == null) + return null; + + name = name.trim(); + name = name.toLowerCase(); + if (name.startsWith(HMAC_NAME_PREFIX)) + return HMacFactory.getInstance(name); + + if (name.startsWith(OMAC_PREFIX)) + { + name = name.substring(OMAC_PREFIX.length()); + IBlockCipher cipher = CipherFactory.getInstance(name); + if (cipher == null) + return null; + return new OMAC(cipher); + } + IMac result = null; + if (name.equalsIgnoreCase(UHASH32)) + result = new UHash32(); + else if (name.equalsIgnoreCase(UMAC32)) + result = new UMac32(); + else if (name.equalsIgnoreCase(TMMH16)) + result = new TMMH16(); + + if (result != null && ! result.selfTest()) + throw new InternalError(result.name()); + + return result; + } + + /** + * Returns a {@link Set} of names of MAC algorithms supported by this + * Factory. + * + * @return a {@link Set} of MAC names (Strings). + */ + public static final Set getNames() + { + synchronized (MacFactory.class) + { + if (names == null) + { + HashSet hs = new HashSet(); + hs.addAll(HMacFactory.getNames()); + hs.add(UHASH32); + hs.add(UMAC32); + hs.add(TMMH16); + for (Iterator it = CipherFactory.getNames().iterator(); it.hasNext();) + hs.add(OMAC_PREFIX + it.next()); + + names = Collections.unmodifiableSet(hs); + } + } + return names; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/MacInputStream.java b/libjava/classpath/gnu/javax/crypto/mac/MacInputStream.java new file mode 100644 index 000000000..7ea808aa9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/MacInputStream.java @@ -0,0 +1,124 @@ +/* MacInputStream.java -- + Copyright (C) 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.crypto.mac; + +import java.io.FilterInputStream; +import java.io.InputStream; +import java.io.IOException; + +/** + * A filtering input stream that computes a MAC (message authentication code) + * over all data read from the stream. + */ +public class MacInputStream + extends FilterInputStream +{ + /** The digesting state. The MAC is updated only if this flag is true. */ + private boolean digesting; + /** The MAC being updated. */ + private IMac mac; + + /** + * Creates a new MacInputStream. The stream is initially set to digest data + * written, the mac argument must have already been initialized, and + * the mac argument is not cloned. + * + * @param in The underlying input stream. + * @param mac The mac instance to use. + */ + public MacInputStream(InputStream in, IMac mac) + { + super(in); + if (mac == null) + throw new NullPointerException(); + this.mac = mac; + digesting = true; + } + + /** + * Returns the MAC this stream is updating. + * + * @return The MAC. + */ + public IMac getMac() + { + return mac; + } + + /** + * Sets the MAC this stream is updating, which must have already been + * initialized. The argument is not cloned by this method. + * + * @param mac The new MAC. + * @throws NullPointerException If the argument is null. + */ + public void setMac(IMac mac) + { + if (mac == null) + throw new NullPointerException(); + this.mac = mac; + } + + /** + * Turns the digesting state on or off. When off, the MAC will not be updated + * when data is written to the stream. + * + * @param flag The new digesting state. + */ + public void on(boolean flag) + { + digesting = flag; + } + + public int read() throws IOException + { + int i = in.read(); + if (digesting && i != -1) + mac.update((byte) i); + return i; + } + + public int read(byte[] buf, int off, int len) throws IOException + { + int i = in.read(buf, off, len); + if (digesting && i != -1) + mac.update(buf, off, i); + return i; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/MacOutputStream.java b/libjava/classpath/gnu/javax/crypto/mac/MacOutputStream.java new file mode 100644 index 000000000..2aa352d75 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/MacOutputStream.java @@ -0,0 +1,123 @@ +/* MacOutputStream.java -- + Copyright (C) 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.crypto.mac; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * A filtering output stream that computes a MAC (message authentication code) + * over all data written to the stream. + */ +public class MacOutputStream + extends FilterOutputStream +{ + /** The digesting state. The MAC is updated only if this flag is true. */ + private boolean digesting; + /** The MAC being updated. */ + private IMac mac; + + /** + * Creates a new MacOutputStream. The stream is initially set + * to digest data written, the mac argument must have already + * been initialized, and the mac argument is not + * cloned. + * + * @param out The underlying output stream. + * @param mac The mac instance to use. + */ + public MacOutputStream(OutputStream out, IMac mac) + { + super(out); + if (mac == null) + throw new NullPointerException(); + this.mac = mac; + digesting = true; + } + + /** + * Returns the MAC this stream is updating. + * + * @return The MAC. + */ + public IMac getMac() + { + return mac; + } + + /** + * Sets the MAC this stream is updating, which must have already been + * initialized. The argument is not cloned by this method. + * + * @param mac The non-null new MAC. + * @throws NullPointerException If the argument is null. + */ + public void setMac(IMac mac) + { + if (mac == null) + throw new NullPointerException(); + this.mac = mac; + } + + /** + * Turns the digesting state on or off. When off, the MAC will not be updated + * when data is written to the stream. + * + * @param flag The new digesting state. + */ + public void on(boolean flag) + { + digesting = flag; + } + + public void write(int b) throws IOException + { + if (digesting) + mac.update((byte) b); + out.write(b); + } + + public void write(byte[] buf, int off, int len) throws IOException + { + if (digesting) + mac.update(buf, off, len); + out.write(buf, off, len); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/OMAC.java b/libjava/classpath/gnu/javax/crypto/mac/OMAC.java new file mode 100644 index 000000000..6758b314f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/OMAC.java @@ -0,0 +1,303 @@ +/* OMAC.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.mac; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.util.Util; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.mode.IMode; + +import java.security.InvalidKeyException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Logger; + +/** + * The One-Key CBC MAC, OMAC. This message authentication code is based on a + * block cipher in CBC mode. + *

+ * References: + *

    + *
  1. Tetsu Iwata and Kaoru Kurosawa, OMAC: One-Key CBC + * MAC.
  2. + *
+ */ +public class OMAC + implements IMac +{ + private static final Logger log = Logger.getLogger(OMAC.class.getName()); + private static final byte C1 = (byte) 0x87; + private static final byte C2 = 0x1b; + // Test key for OMAC-AES-128 + private static final byte[] KEY0 = + Util.toBytesFromString("2b7e151628aed2a6abf7158809cf4f3c"); + // Test MAC for zero-length input. + private static final byte[] DIGEST0 = + Util.toBytesFromString("bb1d6929e95937287fa37d129b756746"); + private static Boolean valid; + private final IBlockCipher cipher; + private final String name; + private IMode mode; + private int blockSize; + private int outputSize; + private byte[] Lu, Lu2; + private byte[] M; + private byte[] Y; + private boolean init; + private int index; + + public OMAC(IBlockCipher cipher) + { + this.cipher = cipher; + this.name = "OMAC-" + cipher.name(); + } + + public Object clone() + { + return new OMAC(cipher); + } + + public String name() + { + return name; + } + + public int macSize() + { + return outputSize; + } + + public void init(Map attrib) throws InvalidKeyException + { + HashMap attrib2 = new HashMap(); + attrib2.put(IBlockCipher.KEY_MATERIAL, attrib.get(MAC_KEY_MATERIAL)); + cipher.reset(); + cipher.init(attrib2); + blockSize = cipher.currentBlockSize(); + Integer os = (Integer) attrib.get(TRUNCATED_SIZE); + if (os != null) + { + outputSize = os.intValue(); + if (outputSize < 0 || outputSize > blockSize) + throw new IllegalArgumentException("truncated size out of range"); + } + else + outputSize = blockSize; + + byte[] L = new byte[blockSize]; + cipher.encryptBlock(L, 0, L, 0); + if (Configuration.DEBUG) + log.fine("L = " + Util.toString(L).toLowerCase()); + if (Lu != null) + { + Arrays.fill(Lu, (byte) 0); + if (Lu.length != blockSize) + Lu = new byte[blockSize]; + } + else + Lu = new byte[blockSize]; + if (Lu2 != null) + { + Arrays.fill(Lu2, (byte) 0); + if (Lu2.length != blockSize) + Lu2 = new byte[blockSize]; + } + else + Lu2 = new byte[blockSize]; + + boolean msb = (L[0] & 0x80) != 0; + for (int i = 0; i < blockSize; i++) + { + Lu[i] = (byte)(L[i] << 1 & 0xFF); + if (i + 1 < blockSize) + Lu[i] |= (byte)((L[i + 1] & 0x80) >> 7); + } + if (msb) + { + if (blockSize == 16) + Lu[Lu.length - 1] ^= C1; + else if (blockSize == 8) + Lu[Lu.length - 1] ^= C2; + else + throw new IllegalArgumentException("unsupported cipher block size: " + + blockSize); + } + if (Configuration.DEBUG) + log.fine("Lu = " + Util.toString(Lu).toLowerCase()); + msb = (Lu[0] & 0x80) != 0; + for (int i = 0; i < blockSize; i++) + { + Lu2[i] = (byte)(Lu[i] << 1 & 0xFF); + if (i + 1 < blockSize) + Lu2[i] |= (byte)((Lu[i + 1] & 0x80) >> 7); + } + if (msb) + { + if (blockSize == 16) + Lu2[Lu2.length - 1] ^= C1; + else + Lu2[Lu2.length - 1] ^= C2; + } + if (Configuration.DEBUG) + log.fine("Lu2 = " + Util.toString(Lu2).toLowerCase()); + if (M != null) + { + Arrays.fill(M, (byte) 0); + if (M.length != blockSize) + M = new byte[blockSize]; + } + else + M = new byte[blockSize]; + if (Y != null) + { + Arrays.fill(Y, (byte) 0); + if (Y.length != blockSize) + Y = new byte[blockSize]; + } + else + Y = new byte[blockSize]; + + index = 0; + init = true; + } + + public void update(byte b) + { + if (! init) + throw new IllegalStateException("not initialized"); + if (index == M.length) + { + process(); + index = 0; + } + M[index++] = b; + } + + public void update(byte[] buf, int off, int len) + { + if (! init) + throw new IllegalStateException("not initialized"); + if (off < 0 || len < 0 || off + len > buf.length) + throw new IndexOutOfBoundsException("size=" + buf.length + "; off=" + off + + "; len=" + len); + for (int i = 0; i < len;) + { + if (index == blockSize) + { + process(); + index = 0; + } + int count = Math.min(blockSize - index, len - i); + System.arraycopy(buf, off + i, M, index, count); + index += count; + i += count; + } + } + + public byte[] digest() + { + byte[] b = new byte[outputSize]; + digest(b, 0); + return b; + } + + public void digest(byte[] out, int off) + { + if (! init) + throw new IllegalStateException("not initialized"); + if (off < 0 || off + outputSize > out.length) + throw new IndexOutOfBoundsException("size=" + out.length + "; off=" + off + + "; len=" + outputSize); + byte[] T = new byte[blockSize]; + byte[] L = Lu; + if (index < blockSize) + { + M[index++] = (byte) 0x80; + while (index < blockSize) + M[index++] = 0; + L = Lu2; + } + for (int i = 0; i < blockSize; i++) + T[i] = (byte)(M[i] ^ Y[i] ^ L[i]); + cipher.encryptBlock(T, 0, T, 0); + System.arraycopy(T, 0, out, off, outputSize); + reset(); + } + + public void reset() + { + index = 0; + if (Y != null) + Arrays.fill(Y, (byte) 0); + if (M != null) + Arrays.fill(M, (byte) 0); + } + + public boolean selfTest() + { + OMAC mac = new OMAC(CipherFactory.getInstance(Registry.AES_CIPHER)); + mac.reset(); + Map attr = new HashMap(); + attr.put(MAC_KEY_MATERIAL, KEY0); + byte[] digest = null; + try + { + mac.init(attr); + digest = mac.digest(); + } + catch (Exception x) + { + return false; + } + if (digest == null) + return false; + return Arrays.equals(DIGEST0, digest); + } + + private void process() + { + for (int i = 0; i < blockSize; i++) + M[i] = (byte)(M[i] ^ Y[i]); + cipher.encryptBlock(M, 0, Y, 0); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/TMMH16.java b/libjava/classpath/gnu/javax/crypto/mac/TMMH16.java new file mode 100644 index 000000000..3427317ab --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/TMMH16.java @@ -0,0 +1,339 @@ +/* TMMH16.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.mac; + +import gnu.java.security.Registry; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; + +import java.security.InvalidKeyException; +import java.util.Map; + +/** + * TMMH is a universal hash function suitable for message + * authentication in the Wegman-Carter paradigm, as in the Stream Cipher + * Security Transform. It is simple, quick, and especially appropriate for + * Digital Signal Processors and other processors with a fast multiply + * operation, though a straightforward implementation requires storage equal in + * length to the largest message to be hashed. + *

+ * TMMH is a simple hash function which maps a key and a message to a + * hash value. There are two versions of TMMH: TMMH/16 and TMMH/32. TMMH + * can be used as a message authentication code, as described in Section 5 (see + * References). + *

+ * The key, message, and hash value are all octet strings, and the lengths of + * these quantities are denoted as KEY_LENGTH, + * MESSAGE_LENGTH, and TAG_LENGTH, respectively. + * The values of KEY_LENGTH and TAG_LENGTH + * MUST be fixed for any particular fixed value of the key, and + * must obey the alignment restrictions described below. + *

+ * The parameter MAX_HASH_LENGTH, which denotes the maximum + * value which MESSAGE_LENGTH may take, is equal to + * KEY_LENGTH - TAG_LENGTH. + *

+ * References: + *

    + *
  1. The + * Truncated Multi-Modular Hash Function (TMMH), David A. McGrew.
  2. + *
+ */ +public class TMMH16 + extends BaseMac + implements Cloneable +{ + public static final String TAG_LENGTH = "gnu.crypto.mac.tmmh.tag.length"; + public static final String KEYSTREAM = "gnu.crypto.mac.tmmh.keystream"; + public static final String PREFIX = "gnu.crypto.mac.tmmh.prefix"; + private static final int P = (1 << 16) + 1; // the TMMH/16 prime + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + private int tagWords = 0; // the tagLength expressed in words + private IRandom keystream = null; // the keystream generator + private byte[] prefix; // mask to use when operating as an authentication f. + private long keyWords; // key words counter + private long msgLength; // in bytes + private long msgWords; // should be = msgLength * WORD_LENGTH + private int[] context; // the tmmh running context; length == TAG_WORDS + private int[] K0; // the first TAG_WORDS words of the keystream + private int[] Ki; // the sliding TAG_WORDS words of the keystream + private int Mi; // current message word being constructed + + /** Trivial 0-arguments constructor. */ + public TMMH16() + { + super(Registry.TMMH16); + } + + public int macSize() + { + return tagWords * 2; + } + + public void init(Map attributes) throws InvalidKeyException, + IllegalStateException + { + int wantTagLength = 0; + Integer tagLength = (Integer) attributes.get(TAG_LENGTH); // get tag length + if (tagLength == null) + { + if (tagWords == 0) // was never set + throw new IllegalArgumentException(TAG_LENGTH); + // else re-use + } + else // check if positive and is divisible by WORD_LENGTH + { + wantTagLength = tagLength.intValue(); + if (wantTagLength < 2 || (wantTagLength % 2 != 0)) + throw new IllegalArgumentException(TAG_LENGTH); + else if (wantTagLength > (512 / 8)) // 512-bits is our maximum + throw new IllegalArgumentException(TAG_LENGTH); + + tagWords = wantTagLength / 2; // init local vars + K0 = new int[tagWords]; + Ki = new int[tagWords]; + context = new int[tagWords]; + } + + prefix = (byte[]) attributes.get(PREFIX); + if (prefix == null) // default to all-zeroes + prefix = new byte[tagWords * 2]; + else // ensure it's as long as it should + { + if (prefix.length != tagWords * 2) + throw new IllegalArgumentException(PREFIX); + } + + IRandom prng = (IRandom) attributes.get(KEYSTREAM); // get keystream + if (prng == null) + { + if (keystream == null) + throw new IllegalArgumentException(KEYSTREAM); + // else reuse + } + else + keystream = prng; + + reset(); // reset context variables + for (int i = 0; i < tagWords; i++) // init starting key words + Ki[i] = K0[i] = getNextKeyWord(keystream); + } + + // The words of the key are denoted as K[1], K[2], ..., K[KEY_WORDS], and the + // words of the message (after zero padding, if needed) are denoted as M[1], + // M[2], ..., M[MSG_WORDS], where MSG_WORDS is the smallest number such that + // 2 * MSG_WORDS is at least MESSAGE_LENGTH, and KEY_WORDS is KEY_LENGTH / 2. + // + // If MESSAGE_LENGTH is greater than MAX_HASH_LENGTH, then the value of + // TMMH/16 is undefined. Implementations MUST indicate an error if asked to + // hash a message with such a length. Otherwise, the hash value is defined + // to be the length TAG_WORDS sequence of words in which the j-th word in the + // sequence is defined as + // + // [ [ K[j] * MESSAGE_LENGTH +32 K[j+1] * M[1] +32 K[j+2] * M[2] + // +32 ... K[j+MSG_WORDS] * M[MSG_WORDS] ] modulo p ] modulo 2^16 + // + // where j ranges from 1 to TAG_WORDS. + public void update(byte b) + { + this.update(b, keystream); + } + + public void update(byte[] b, int offset, int len) + { + for (int i = 0; i < len; i++) + this.update(b[offset + i], keystream); + } + + // For TMMH/16, KEY_LENGTH and TAG_LENGTH MUST be a multiple of two. The key, + // message, and hash value are treated as a sequence of unsigned sixteen bit + // integers in network byte order. (In this section, we call such an integer + // a word.) If MESSAGE_LENGTH is odd, then a zero byte is appended to the + // message to align it on a word boundary, though this process does not + // change the value of MESSAGE_LENGTH. + // + // ... Otherwise, the hash value is defined to be the length TAG_WORDS + // sequence of words in which the j-th word in the sequence is defined as + // + // [ [ K[j] * MESSAGE_LENGTH +32 K[j+1] * M[1] +32 K[j+2] * M[2] + // +32 ... K[j+MSG_WORDS] * M[MSG_WORDS] ] modulo p ] modulo 2^16 + // + // where j ranges from 1 to TAG_WORDS. + // + // Here, TAG_WORDS is equal to TAG_LENGTH / 2, and p is equal to 2^16 + 1. + // The symbol * denotes multiplication and the symbol +32 denotes addition + // modulo 2^32. + public byte[] digest() + { + return this.digest(keystream); + } + + public void reset() + { + msgLength = msgWords = keyWords = 0L; + Mi = 0; + for (int i = 0; i < tagWords; i++) + context[i] = 0; + } + + public boolean selfTest() + { + if (valid == null) + { + // TODO: compute and test equality with one known vector + valid = Boolean.TRUE; + } + return valid.booleanValue(); + } + + public Object clone() throws CloneNotSupportedException + { + TMMH16 result = (TMMH16) super.clone(); + if (this.keystream != null) + result.keystream = (IRandom) this.keystream.clone(); + if (this.prefix != null) + result.prefix = (byte[]) this.prefix.clone(); + if (this.context != null) + result.context = (int[]) this.context.clone(); + if (this.K0 != null) + result.K0 = (int[]) this.K0.clone(); + if (this.Ki != null) + result.Ki = (int[]) this.Ki.clone(); + return result; + } + + /** + * Similar to the same method with one argument, but uses the designated + * random number generator to compute needed keying material. + * + * @param b the byte to process. + * @param prng the source of randomness to use. + */ + public void update(byte b, IRandom prng) + { + Mi <<= 8; // update message buffer + Mi |= b & 0xFF; + msgLength++; // update message length (bytes) + if (msgLength % 2 == 0) // got a full word + { + msgWords++; // update message words counter + System.arraycopy(Ki, 1, Ki, 0, tagWords - 1); // 1. shift Ki up by 1 + Ki[tagWords - 1] = getNextKeyWord(prng); // 2. fill last box of Ki + long t; // temp var to allow working in modulo 2^32 + for (int i = 0; i < tagWords; i++) // 3. update context + { + t = context[i] & 0xFFFFFFFFL; + t += Ki[i] * Mi; + context[i] = (int) t; + } + Mi = 0; // reset message buffer + } + } + + /** + * Similar to the same method with three arguments, but uses the designated + * random number generator to compute needed keying material. + * + * @param b the byte array to process. + * @param offset the starting offset in b to start considering + * the bytes to process. + * @param len the number of bytes in b starting from + * offset to process. + * @param prng the source of randomness to use. + */ + public void update(byte[] b, int offset, int len, IRandom prng) + { + for (int i = 0; i < len; i++) + this.update(b[offset + i], prng); + } + + /** + * Similar to the same method with no arguments, but uses the designated + * random number generator to compute needed keying material. + * + * @param prng the source of randomness to use. + * @return the final result of the algorithm. + */ + public byte[] digest(IRandom prng) + { + doFinalRound(prng); + byte[] result = new byte[tagWords * 2]; + for (int i = 0, j = 0; i < tagWords; i++) + { + result[j] = (byte)((context[i] >>> 8) ^ prefix[j]); + j++; + result[j] = (byte)(context[i] ^ prefix[j]); + j++; + } + reset(); + return result; + } + + private int getNextKeyWord(IRandom prng) + { + int result = 0; + try + { + result = (prng.nextByte() & 0xFF) << 8 | (prng.nextByte() & 0xFF); + } + catch (LimitReachedException x) + { + throw new RuntimeException(String.valueOf(x)); + } + keyWords++; // update key words counter + return result; + } + + private void doFinalRound(IRandom prng) + { + long limit = msgLength; // formula works on real message length + while (msgLength % 2 != 0) + update((byte) 0x00, prng); + long t; + for (int i = 0; i < tagWords; i++) + { + t = context[i] & 0xFFFFFFFFL; + t += K0[i] * limit; + t %= P; + context[i] = (int) t; + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/UHash32.java b/libjava/classpath/gnu/javax/crypto/mac/UHash32.java new file mode 100644 index 000000000..53513eda9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/UHash32.java @@ -0,0 +1,758 @@ +/* UHash32.java -- + 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.crypto.mac; + +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.prng.UMacGenerator; + +import java.io.ByteArrayOutputStream; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.util.HashMap; +import java.util.Map; + +/** + * UHASH is a keyed hash function, which takes as input a string of + * arbitrary length, and produces as output a string of fixed length (such as 8 + * bytes). The actual output length depends on the parameter UMAC-OUTPUT-LEN. + *

+ * UHASH has been shown to be epsilon-ASU ("Almost Strongly + * Universal"), where epsilon is a small (parameter-dependent) real number. + * Informally, saying that a keyed hash function is epsilon-ASU means + * that for any two distinct fixed input strings, the two outputs of the hash + * function with a random key "look almost like a pair of random strings". The + * number epsilon measures how non-random the output strings may be. + *

+ * UHASH has been designed to be fast by exploiting several + * architectural features of modern commodity processors. It was specifically + * designed for use in UMAC. But UHASH is useful beyond that + * domain, and can be easily adopted for other purposes. + *

+ * UHASH does its work in three layers. First, a hash function called + * NH is used to compress input messages into strings which are + * typically many times smaller than the input message. Second, the compressed + * message is hashed with an optimized polynomial hash function into a + * fixed-length 16-byte string. Finally, the 16-byte string is hashed using an + * inner-product hash into a string of length WORD-LEN bytes. These + * three layers are repeated (with a modified key) until the outputs total + * UMAC-OUTPUT-LEN bytes. + *

+ * References: + *

    + *
  1. + * UMAC: Message Authentication Code using Universal Hashing.
    + * T. Krovetz, J. Black, S. Halevi, A. Hevia, H. Krawczyk, and P. Rogaway.
  2. + *
+ */ +public class UHash32 + extends BaseMac +{ + // UMAC prime values + private static final BigInteger PRIME_19 = BigInteger.valueOf(0x7FFFFL); + private static final BigInteger PRIME_32 = BigInteger.valueOf(0xFFFFFFFBL); + private static final BigInteger PRIME_36 = BigInteger.valueOf(0xFFFFFFFFBL); + private static final BigInteger PRIME_64 = new BigInteger(1, new byte[] { + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xC5 }); + private static final BigInteger PRIME_128 = new BigInteger(1, new byte[] { + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x61 }); + static final BigInteger TWO = BigInteger.valueOf(2L); + static final long BOUNDARY = TWO.shiftLeft(17).longValue(); + // 2**64 - 2**32 + static final BigInteger LOWER_RANGE = TWO.pow(64).subtract(TWO.pow(32)); + // 2**128 - 2**96 + static final BigInteger UPPER_RANGE = TWO.pow(128).subtract(TWO.pow(96)); + static final byte[] ALL_ZEROES = new byte[32]; + int streams; + L1Hash32[] l1hash; + + /** Trivial 0-arguments constructor. */ + public UHash32() + { + super("uhash32"); + } + + /** + * Private constructor for cloning purposes. + * + * @param that the instance to clone. + */ + private UHash32(UHash32 that) + { + this(); + + this.streams = that.streams; + if (that.l1hash != null) + { + this.l1hash = new L1Hash32[that.streams]; + for (int i = 0; i < that.streams; i++) + if (that.l1hash[i] != null) + this.l1hash[i] = (L1Hash32) that.l1hash[i].clone(); + } + } + + /** + * The prime numbers used in UMAC are: + *
+   *   +-----+--------------------+---------------------------------------+
+   *   |  x  | prime(x) [Decimal] | prime(x) [Hexadecimal]                |
+   *   +-----+--------------------+---------------------------------------+
+   *   | 19  | 2^19  - 1          | 0x0007FFFF                            |
+   *   | 32  | 2^32  - 5          | 0xFFFFFFFB                            |
+   *   | 36  | 2^36  - 5          | 0x0000000F FFFFFFFB                   |
+   *   | 64  | 2^64  - 59         | 0xFFFFFFFF FFFFFFC5                   |
+   *   | 128 | 2^128 - 159        | 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFF61 |
+   *   +-----+--------------------+---------------------------------------+
+   *
+ * + * @param n a number of bits. + * @return the largest prime number less than 2**n. + */ + static final BigInteger prime(int n) + { + switch (n) + { + case 19: + return PRIME_19; + case 32: + return PRIME_32; + case 36: + return PRIME_36; + case 64: + return PRIME_64; + case 128: + return PRIME_128; + default: + throw new IllegalArgumentException("Undefined prime(" + + String.valueOf(n) + ")"); + } + } + + public Object clone() + { + return new UHash32(this); + } + + public int macSize() + { + return UMac32.OUTPUT_LEN; + } + + public void init(Map attributes) throws InvalidKeyException, + IllegalStateException + { + byte[] K = (byte[]) attributes.get(MAC_KEY_MATERIAL); + if (K == null) + throw new InvalidKeyException("Null Key"); + if (K.length != UMac32.KEY_LEN) + throw new InvalidKeyException("Invalid Key length: " + + String.valueOf(K.length)); + // Calculate iterations needed to make UMAC-OUTPUT-LEN bytes + streams = (UMac32.OUTPUT_LEN + 3) / 4; + // Define total key needed for all iterations using UMacGenerator. + // L1Key and L3Key1 both reuse most key between iterations. + IRandom kdf1 = new UMacGenerator(); + IRandom kdf2 = new UMacGenerator(); + IRandom kdf3 = new UMacGenerator(); + IRandom kdf4 = new UMacGenerator(); + Map map = new HashMap(); + map.put(IBlockCipher.KEY_MATERIAL, K); + map.put(UMacGenerator.INDEX, Integer.valueOf(0)); + kdf1.init(map); + map.put(UMacGenerator.INDEX, Integer.valueOf(1)); + kdf2.init(map); + map.put(UMacGenerator.INDEX, Integer.valueOf(2)); + kdf3.init(map); + map.put(UMacGenerator.INDEX, Integer.valueOf(3)); + kdf4.init(map); + // need to generate all bytes for use later in a Toepliz construction + byte[] L1Key = new byte[UMac32.L1_KEY_LEN + (streams - 1) * 16]; + try + { + kdf1.nextBytes(L1Key, 0, L1Key.length); + } + catch (LimitReachedException x) + { + x.printStackTrace(System.err); + throw new RuntimeException("KDF for L1Key reached limit"); + } + + l1hash = new L1Hash32[streams]; + for (int i = 0; i < streams; i++) + { + byte[] k1 = new byte[UMac32.L1_KEY_LEN]; + System.arraycopy(L1Key, i * 16, k1, 0, UMac32.L1_KEY_LEN); + byte[] k2 = new byte[24]; + try + { + kdf2.nextBytes(k2, 0, 24); + } + catch (LimitReachedException x) + { + x.printStackTrace(System.err); + throw new RuntimeException("KDF for L2Key reached limit"); + } + byte[] k31 = new byte[64]; + try + { + kdf3.nextBytes(k31, 0, 64); + } + catch (LimitReachedException x) + { + x.printStackTrace(System.err); + throw new RuntimeException("KDF for L3Key1 reached limit"); + } + byte[] k32 = new byte[4]; + try + { + kdf4.nextBytes(k32, 0, 4); + } + catch (LimitReachedException x) + { + x.printStackTrace(System.err); + throw new RuntimeException("KDF for L3Key2 reached limit"); + } + L1Hash32 mac = new L1Hash32(); + mac.init(k1, k2, k31, k32); + l1hash[i] = mac; + } + } + + public void update(byte b) + { + for (int i = 0; i < streams; i++) + l1hash[i].update(b); + } + + public void update(byte[] b, int offset, int len) + { + for (int i = 0; i < len; i++) + this.update(b[offset + i]); + } + + public byte[] digest() + { + byte[] result = new byte[UMac32.OUTPUT_LEN]; + for (int i = 0; i < streams; i++) + { + byte[] partialResult = l1hash[i].digest(); + System.arraycopy(partialResult, 0, result, 4 * i, 4); + } + reset(); + return result; + } + + public void reset() + { + for (int i = 0; i < streams; i++) + l1hash[i].reset(); + } + + public boolean selfTest() + { + return true; + } + + /** + * First hash stage of the UHash32 algorithm. + */ + class L1Hash32 + implements Cloneable + { + private int[] key; // key material as an array of 32-bit ints + private byte[] buffer; // work buffer L1_KEY_LEN long + private int count; // meaningful bytes in buffer + private ByteArrayOutputStream Y; + private long totalCount; + private L2Hash32 l2hash; + private L3Hash32 l3hash; + + /** Trivial 0-arguments constructor. */ + L1Hash32() + { + super(); + + key = new int[UMac32.L1_KEY_LEN / 4]; + buffer = new byte[UMac32.L1_KEY_LEN]; + count = 0; + Y = new ByteArrayOutputStream(); + totalCount = 0L; + } + + /** + * Private constructor for cloning purposes. + * + * @param that the instance to clone. + */ + private L1Hash32(L1Hash32 that) + { + this(); + + System.arraycopy(that.key, 0, this.key, 0, that.key.length); + System.arraycopy(that.buffer, 0, this.buffer, 0, that.count); + this.count = that.count; + byte[] otherY = that.Y.toByteArray(); + this.Y.write(otherY, 0, otherY.length); + this.totalCount = that.totalCount; + if (that.l2hash != null) + this.l2hash = (L2Hash32) that.l2hash.clone(); + if (that.l3hash != null) + this.l3hash = (L3Hash32) that.l3hash.clone(); + } + + public Object clone() + { + return new L1Hash32(this); + } + + public void init(byte[] k1, byte[] k2, byte[] k31, byte[] k32) + { + for (int i = 0, j = 0; i < (UMac32.L1_KEY_LEN / 4); i++) + key[i] = k1[j++] << 24 + | (k1[j++] & 0xFF) << 16 + | (k1[j++] & 0xFF) << 8 + | (k1[j++] & 0xFF); + l2hash = new L2Hash32(k2); + l3hash = new L3Hash32(k31, k32); + } + + public void update(byte b) + { + // Break M into L1_KEY_LEN byte chunks (final chunk may be shorter) + + // Let M_1, M_2, ..., M_t be strings so that M = M_1 || M_2 || .. || + // M_t, and length(M_i) = L1_KEY_LEN for all 0 < i < t. + + // For each chunk, except the last: endian-adjust, NH hash + // and add bit-length. Use results to build Y. + buffer[count] = b; + count++; + totalCount++; + if (count >= UMac32.L1_KEY_LEN) + { + byte[] y = nh32(UMac32.L1_KEY_LEN); + Y.write(y, 0, 8); + + count = 0; + + // For each iteration, extract key and three-layer hash. + // If length(M) <= L1_KEY_LEN, then skip L2-HASH. + if (Y.size() == 16) // we already hashed twice L1_KEY_LEN + { + byte[] A = Y.toByteArray(); + Y.reset(); + l2hash.update(A, 0, 16); + } + } + } + + public byte[] digest() + { + // For the last chunk: pad to 32-byte boundary, endian-adjust, + // NH hash and add bit-length. Concatenate the result to Y. + if (count != 0) + { + if (count % 32 != 0) + { + int limit = 32 * ((count + 31) / 32); + System.arraycopy(ALL_ZEROES, 0, buffer, count, limit - count); + count += limit - count; + } + byte[] y = nh32(count); + Y.write(y, 0, 8); + } + byte[] A = Y.toByteArray(); + Y.reset(); + byte[] B; + if (totalCount <= UMac32.L1_KEY_LEN) + { + // we might have 'update'd the bytes already. check + if (A.length == 0) // we did + B = l2hash.digest(); + else // did not + { + B = new byte[16]; + System.arraycopy(A, 0, B, 8, 8); + } + } + else + { + if (A.length != 0) + l2hash.update(A, 0, A.length); + B = l2hash.digest(); + } + byte[] result = l3hash.digest(B); + reset(); + return result; + } + + public void reset() + { + count = 0; + Y.reset(); + totalCount = 0L; + if (l2hash != null) + l2hash.reset(); + } + + /** + * 5.1 NH-32: NH hashing with a 32-bit word size. + * + * @param len count of bytes, divisible by 32, in buffer to process + * @return Y, string of length 8 bytes. + */ + private byte[] nh32(int len) + { + // Break M and K into 4-byte chunks + int t = len / 4; + // Let M_1, M_2, ..., M_t be 4-byte strings + // so that M = M_1 || M_2 || .. || M_t. + // Let K_1, K_2, ..., K_t be 4-byte strings + // so that K_1 || K_2 || .. || K_t is a prefix of K. + int[] m = new int[t]; + int i; + int j = 0; + for (i = 0, j = 0; i < t; i++) + m[i] = buffer[j++] << 24 + | (buffer[j++] & 0xFF) << 16 + | (buffer[j++] & 0xFF) << 8 + | (buffer[j++] & 0xFF); + // Perform NH hash on the chunks, pairing words for multiplication + // which are 4 apart to accommodate vector-parallelism. + long result = len * 8L; + for (i = 0; i < t; i += 8) + { + result += ((m[i + 0] + key[i + 0]) & 0xFFFFFFFFL) + * ((m[i + 4] + key[i + 4]) & 0xFFFFFFFFL); + result += ((m[i + 1] + key[i + 1]) & 0xFFFFFFFFL) + * ((m[i + 5] + key[i + 5]) & 0xFFFFFFFFL); + result += ((m[i + 2] + key[i + 2]) & 0xFFFFFFFFL) + * ((m[i + 6] + key[i + 6]) & 0xFFFFFFFFL); + result += ((m[i + 3] + key[i + 3]) & 0xFFFFFFFFL) + * ((m[i + 7] + key[i + 7]) & 0xFFFFFFFFL); + } + return new byte[] { + (byte)(result >>> 56), (byte)(result >>> 48), + (byte)(result >>> 40), (byte)(result >>> 32), + (byte)(result >>> 24), (byte)(result >>> 16), + (byte)(result >>> 8), (byte) result }; + } + } + + /** + * Second hash stage of the UHash32 algorithm. + *

+ * 5.4 L2-HASH-32: Second-layer hash. + *

+ */ + class L2Hash32 + implements Cloneable + { + private BigInteger k64, k128; + private BigInteger y; + private boolean highBound; + private long bytesSoFar; + private ByteArrayOutputStream buffer; + + L2Hash32(byte[] K) + { + super(); + + if (K.length != 24) + throw new ExceptionInInitializerError("K length is not 24"); + // Extract keys and restrict to special key-sets + // Mask64 = uint2str(0x01FFFFFF01FFFFFF, 8); + // Mask128 = uint2str(0x01FFFFFF01FFFFFF01FFFFFF01FFFFFF, 16); + // k64 = str2uint(K[1..8] and Mask64); + // k128 = str2uint(K[9..24] and Mask128); + int i = 0; + k64 = new BigInteger(1, new byte[] { + (byte)(K[i++] & 0x01), (byte)(K[i++] & 0xFF), + (byte)(K[i++] & 0xFF), (byte)(K[i++] & 0xFF), + (byte)(K[i++] & 0x01), (byte)(K[i++] & 0xFF), + (byte)(K[i++] & 0xFF), (byte)(K[i++] & 0xFF) }); + k128 = new BigInteger(1, new byte[] { + (byte)(K[i++] & 0x01), (byte)(K[i++] & 0xFF), + (byte)(K[i++] & 0xFF), (byte)(K[i++] & 0xFF), + (byte)(K[i++] & 0x01), (byte)(K[i++] & 0xFF), + (byte)(K[i++] & 0xFF), (byte)(K[i++] & 0xFF), + (byte)(K[i++] & 0x01), (byte)(K[i++] & 0xFF), + (byte)(K[i++] & 0xFF), (byte)(K[i++] & 0xFF), + (byte)(K[i++] & 0x01), (byte)(K[i++] & 0xFF), + (byte)(K[i++] & 0xFF), (byte)(K[i++] & 0xFF) }); + y = BigInteger.ONE; + highBound = false; + bytesSoFar = 0L; + } + + private L2Hash32(L2Hash32 that) + { + super(); + + this.k64 = that.k64; + this.k128 = that.k128; + this.y = that.y; + this.highBound = that.highBound; + this.bytesSoFar = that.bytesSoFar; + if (that.buffer != null) + { + byte[] thatbuffer = that.buffer.toByteArray(); + this.buffer = new ByteArrayOutputStream(); + this.buffer.write(thatbuffer, 0, thatbuffer.length); + } + } + + public Object clone() + { + return new L2Hash32(this); + } + + // this is called with either 8-bytes or 16-bytes + void update(byte[] b, int offset, int len) + { + if (len == 0) + return; + + if (! highBound) // do the first (only?) 8-bytes + { + poly(64, LOWER_RANGE, k64, b, offset, 8); + bytesSoFar += 8L; + highBound = (bytesSoFar > BOUNDARY); + if (highBound) // if we just crossed the limit then process y + { + poly(128, UPPER_RANGE, k128, yTo16bytes(), 0, 16); + buffer = new ByteArrayOutputStream(); + } + // do the rest if any + update(b, offset + 8, len - 8); + } + else + { // we're already beyond the 2**17 bytes size limit + // process in chuncks of 16 + buffer.write(b, offset, len); + if (buffer.size() > 16) + { + byte[] bb = buffer.toByteArray(); + poly(128, UPPER_RANGE, k128, bb, 0, 16); + if (bb.length > 16) + buffer.write(bb, 16, bb.length - 16); + } + } + } + + byte[] digest() + { + // If M no more than 2^17 bytes, hash under 64-bit prime, + // otherwise, hash first 2^17 bytes under 64-bit prime and + // remainder under 128-bit prime. + if (! highBound) // y is up-to-date + { + // do nothing + } + else // we may have some bytes in buffer + { + byte[] bb = buffer.toByteArray(); + byte[] lastBlock = new byte[16]; + System.arraycopy(bb, 0, lastBlock, 0, bb.length); + lastBlock[bb.length] = (byte) 0x80; + poly(128, UPPER_RANGE, k128, lastBlock, 0, 16); + } + byte[] result = yTo16bytes(); + reset(); + return result; + } + + void reset() + { + y = BigInteger.ONE; + highBound = false; + bytesSoFar = 0L; + if (buffer != null) + buffer.reset(); + } + + private byte[] yTo16bytes() + { + byte[] yy = y.toByteArray(); + byte[] result = new byte[16]; + if (yy.length > 16) + System.arraycopy(yy, yy.length - 16, result, 0, 16); + else + System.arraycopy(yy, 0, result, 16 - yy.length, yy.length); + + return result; + } + + /** + * 5.3 POLY: Polynomial hash Function Name: POLY + * + * @param wordbits positive integer divisible by 8: called with 64 or 128. + * @param maxwordrange positive integer less than 2**wordbits. + * @param k integer in the range 0 .. prime(wordbits) - 1. + * @param M string with length divisible by (wordbits / 8) bytes. return y, + * integer in the range 0 .. prime(wordbits) - 1. + */ + private void poly(int wordbits, BigInteger maxwordrange, BigInteger k, + byte[] M, int off, int len) + { + byte[] mag = new byte[len]; + System.arraycopy(M, off, mag, 0, len); + // Define constants used for fixing out-of-range words + BigInteger p = prime(wordbits); + BigInteger offset = TWO.pow(wordbits).subtract(p); // 2^wordbits - p; + BigInteger marker = p.subtract(BigInteger.ONE); + // Break M into chunks of length wordbytes bytes + // long n = M.length / wordbytes; + // Let M_1, M_2, ..., M_n be strings of length wordbytes bytes + // so that M = M_1 || M_2 || .. || M_n + + // For each input word, compare it with maxwordrange. If larger + // then hash the words 'marker' and (m - offset), both in range. + // for (int i = 0; i < n; i++) { + BigInteger m = new BigInteger(1, mag); + if (m.compareTo(maxwordrange) >= 0) // m >= maxwordrange + { + y = y.multiply(k).add(marker).mod(p); // (k * y + marker) % p; + y = y.multiply(k).add(m.subtract(offset)).mod(p); // (k * y + (m - offset)) % p; + } + else + y = y.multiply(k).add(m).mod(p); // (k * y + m) % p; + } + } + + /** + * Third hash stage of the UHash32 algorithm. + * + */ + class L3Hash32 + implements Cloneable + { + private static final long PRIME_36 = 0x0000000FFFFFFFFBL; + private int[] k = new int[9]; + + /** + * @param K1 string of length 64 bytes. + * @param K2 string of length 4 bytes. + */ + L3Hash32(byte[] K1, byte[] K2) + { + super(); + + // pre-conditions + if (K1.length != 64) + throw new ExceptionInInitializerError("K1 length is not 64"); + if (K2.length != 4) + throw new ExceptionInInitializerError("K2 length is not 4"); + // Break K1 into 8 chunks and convert to integers + for (int i = 0, j = 0; i < 8; i++) + { + long kk = (K1[j++] & 0xFFL) << 56 + | (K1[j++] & 0xFFL) << 48 + | (K1[j++] & 0xFFL) << 40 + | (K1[j++] & 0xFFL) << 32 + | (K1[j++] & 0xFFL) << 24 + | (K1[j++] & 0xFFL) << 16 + | (K1[j++] & 0xFFL) << 8 + | (K1[j++] & 0xFFL); + k[i] = (int)(kk % PRIME_36); + } + k[8] = K2[0] << 24 + | (K2[1] & 0xFF) << 16 + | (K2[2] & 0xFF) << 8 + | (K2[3] & 0xFF); + } + + private L3Hash32(int[] k) + { + super(); + + this.k = k; + } + + public Object clone() + { + return new L3Hash32((int[]) k.clone()); + } + + /** + * @param M string of length 16 bytes. + * @return Y, string of length 4 bytes. + */ + byte[] digest(byte[] M) + { + if (M.length != 16) + throw new IllegalArgumentException("M length is not 16"); + + long m, y = 0L; + for (int i = 0, j = 0; i < 8; i++) + { + // Break M into 8 chunks and convert to integers + m = (M[j++] & 0xFFL) << 8 | (M[j++] & 0xFFL); + // Inner-product hash, extract last 32 bits and affine-translate + // y = (m_1 * k_1 + ... + m_8 * k_8) mod prime(36); + // y = y mod 2^32; + y += (m * (k[i] & 0xFFFFFFFFL)) % PRIME_36; + } + int Y = ((int) y) ^ k[8]; + return new byte[] { + (byte)(Y >>> 24), + (byte)(Y >>> 16), + (byte)(Y >>> 8), + (byte) Y }; + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/UMac32.java b/libjava/classpath/gnu/javax/crypto/mac/UMac32.java new file mode 100644 index 000000000..6f53424ea --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/UMac32.java @@ -0,0 +1,418 @@ +/* UMac32.java -- + 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.crypto.mac; + +import gnu.java.security.Registry; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.Util; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.prng.UMacGenerator; + +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.util.HashMap; +import java.util.Map; + +/** + * The implementation of the UMAC (Universal Message Authentication + * Code). + *

+ * The UMAC algorithms described are parameterized. This means + * that various low-level choices, like the endian convention and the underlying + * cryptographic primitive, have not been fixed. One must choose values for + * these parameters before the authentication tag generated by UMAC (for + * a given message, key, and nonce) becomes fully-defined. In this document we + * provide two collections of parameter settings, and have named the sets + * UMAC16 and UMAC32. The parameter sets have been chosen based + * on experimentation and provide good performance on a wide variety of + * processors. UMAC16 is designed to excel on processors which provide + * small-scale SIMD parallelism of the type found in Intel's MMX and Motorola's + * AltiVec instruction sets, while UMAC32 is designed to do well on + * processors with good 32- and 64- bit support. UMAC32 may take + * advantage of SIMD parallelism in future processors. + *

+ * UMAC has been designed to allow implementations which accommodate + * on-line authentication. This means that pieces of the message may be + * presented to UMAC at different times (but in correct order) and an + * on-line implementation will be able to process the message correctly without + * the need to buffer more than a few dozen bytes of the message. For + * simplicity, the algorithms in this specification are presented as if the + * entire message being authenticated were available at once. + *

+ * To authenticate a message, Msg, one first applies the + * universal hash function, resulting in a string which is typically much + * shorter than the original message. The pseudorandom function is applied to a + * nonce, and the result is used in the manner of a Vernam cipher: the + * authentication tag is the xor of the output from the hash function and the + * output from the pseudorandom function. Thus, an authentication tag is + * generated as + *

+ *     AuthTag = f(Nonce) xor h(Msg)
+ * 
+ *

+ * Here f is the pseudorandom function shared between the sender + * and the receiver, and h is a universal hash function shared by the sender and + * the receiver. In UMAC, a shared key is used to key the pseudorandom + * function f, and then f is used for both tag + * generation and internally to generate all of the bits needed by the universal + * hash function. + *

+ * The universal hash function that we use is called UHASH. It + * combines several software-optimized algorithms into a multi-layered + * structure. The algorithm is moderately complex. Some of this complexity comes + * from extensive speed optimizations. + *

+ * For the pseudorandom function we use the block cipher of the Advanced + * Encryption Standard (AES). + *

+ * The UMAC32 parameters, considered in this implementation are: + *

+ *                                    UMAC32
+ *                                    ------
+ *         WORD-LEN                        4
+ *         UMAC-OUTPUT-LEN                 8
+ *         L1-KEY-LEN                   1024
+ *         UMAC-KEY-LEN                   16
+ *         ENDIAN-FAVORITE               BIG *
+ *         L1-OPERATIONS-SIGN       UNSIGNED
+ * 
+ *

+ * Please note that this UMAC32 differs from the one described in the paper by + * the ENDIAN-FAVORITE value. + *

+ * References: + *

    + *
  1. + * UMAC: Message Authentication Code using Universal Hashing.
    + * T. Krovetz, J. Black, S. Halevi, A. Hevia, H. Krawczyk, and P. Rogaway.
  2. + *
+ */ +public class UMac32 + extends BaseMac +{ + /** + * Property name of the user-supplied Nonce. The value associated to + * this property name is taken to be a byte array. + */ + public static final String NONCE_MATERIAL = "gnu.crypto.umac.nonce.material"; + /** Known test vector. */ + // private static final String TV1 = "3E5A0E09198B0F94"; + // private static final String TV1 = "5FD764A6D3A9FD9D"; + // private static final String TV1 = "48658DE1D9A70304"; + private static final String TV1 = "455ED214A6909F20"; + private static final BigInteger MAX_NONCE_ITERATIONS = BigInteger.ONE.shiftLeft(16 * 8); + // UMAC32 parameters + static final int OUTPUT_LEN = 8; + static final int L1_KEY_LEN = 1024; + static final int KEY_LEN = 16; + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + private byte[] nonce; + private UHash32 uhash32; + private BigInteger nonceReuseCount; + /** The authentication key for this instance. */ + private transient byte[] K; + + /** Trivial 0-arguments constructor. */ + public UMac32() + { + super("umac32"); + } + + /** + * Private constructor for cloning purposes. + * + * @param that the instance to clone. + */ + private UMac32(UMac32 that) + { + this(); + + if (that.K != null) + this.K = (byte[]) that.K.clone(); + if (that.nonce != null) + this.nonce = (byte[]) that.nonce.clone(); + if (that.uhash32 != null) + this.uhash32 = (UHash32) that.uhash32.clone(); + this.nonceReuseCount = that.nonceReuseCount; + } + + public Object clone() + { + return new UMac32(this); + } + + public int macSize() + { + return OUTPUT_LEN; + } + + /** + * Initialising a UMAC instance consists of defining values for the + * following parameters: + *
    + *
  1. Key Material: as the value of the attribute entry keyed by + * {@link #MAC_KEY_MATERIAL}. The value is taken to be a byte array + * containing the user-specified key material. The length of this array, + * if/when defined SHOULD be exactly equal to {@link #KEY_LEN}.
  2. + *
  3. Nonce Material: as the value of the attribute entry keyed by + * {@link #NONCE_MATERIAL}. The value is taken to be a byte array containing + * the user-specified nonce material. The length of this array, if/when + * defined SHOULD be (a) greater than zero, and (b) less or equal to 16 (the + * size of the AES block).
  4. + *
+ *

+ * For convenience, this implementation accepts that not both parameters be + * always specified. + *

+ *

+ * This method throws an exception if no Key Material is specified in + * the input map, and there is no previously set/defined Key Material + * (from an earlier invocation of this method). If a Key Material can + * be used, but no Nonce Material is defined or previously + * set/defined, then a default value of all-zeroes shall be used. + * + * @param attributes one or both of required parameters. + * @throws InvalidKeyException the key material specified is not of the + * correct length. + */ + public void init(Map attributes) throws InvalidKeyException, + IllegalStateException + { + byte[] key = (byte[]) attributes.get(MAC_KEY_MATERIAL); + byte[] n = (byte[]) attributes.get(NONCE_MATERIAL); + boolean newKey = (key != null); + boolean newNonce = (n != null); + if (newKey) + { + if (key.length != KEY_LEN) + throw new InvalidKeyException("Key length: " + + String.valueOf(key.length)); + K = key; + } + else + { + if (K == null) + throw new InvalidKeyException("Null Key"); + } + if (newNonce) + { + if (n.length < 1 || n.length > 16) + throw new IllegalArgumentException("Invalid Nonce length: " + + String.valueOf(n.length)); + if (n.length < 16) // pad with zeroes + { + byte[] newN = new byte[16]; + System.arraycopy(n, 0, newN, 0, n.length); + nonce = newN; + } + else + nonce = n; + + nonceReuseCount = BigInteger.ZERO; + } + else if (nonce == null) // use all-0 nonce if 1st time + { + nonce = new byte[16]; + nonceReuseCount = BigInteger.ZERO; + } + else if (! newKey) // increment nonce if still below max count + { + nonceReuseCount = nonceReuseCount.add(BigInteger.ONE); + if (nonceReuseCount.compareTo(MAX_NONCE_ITERATIONS) >= 0) + { + // limit reached. we SHOULD have a key + throw new InvalidKeyException("Null Key and unusable old Nonce"); + } + BigInteger N = new BigInteger(1, nonce); + N = N.add(BigInteger.ONE).mod(MAX_NONCE_ITERATIONS); + n = N.toByteArray(); + if (n.length == 16) + nonce = n; + else if (n.length < 16) + { + nonce = new byte[16]; + System.arraycopy(n, 0, nonce, 16 - n.length, n.length); + } + else + { + nonce = new byte[16]; + System.arraycopy(n, n.length - 16, nonce, 0, 16); + } + } + else // do nothing, re-use old nonce value + nonceReuseCount = BigInteger.ZERO; + + if (uhash32 == null) + uhash32 = new UHash32(); + + Map map = new HashMap(); + map.put(MAC_KEY_MATERIAL, K); + uhash32.init(map); + } + + public void update(byte b) + { + uhash32.update(b); + } + + public void update(byte[] b, int offset, int len) + { + uhash32.update(b, offset, len); + } + + public byte[] digest() + { + byte[] result = uhash32.digest(); + byte[] pad = pdf(); // pdf(K, nonce); + for (int i = 0; i < OUTPUT_LEN; i++) + result[i] = (byte)(result[i] ^ pad[i]); + + return result; + } + + public void reset() + { + if (uhash32 != null) + uhash32.reset(); + } + + public boolean selfTest() + { + if (valid == null) + { + byte[] key; + try + { + key = "abcdefghijklmnop".getBytes("ASCII"); + } + catch (UnsupportedEncodingException x) + { + throw new RuntimeException("ASCII not supported"); + } + byte[] nonce = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }; + UMac32 mac = new UMac32(); + Map attributes = new HashMap(); + attributes.put(MAC_KEY_MATERIAL, key); + attributes.put(NONCE_MATERIAL, nonce); + try + { + mac.init(attributes); + } + catch (InvalidKeyException x) + { + x.printStackTrace(System.err); + return false; + } + byte[] data = new byte[128]; + data[0] = (byte) 0x80; + mac.update(data, 0, 128); + byte[] result = mac.digest(); + valid = Boolean.valueOf(TV1.equals(Util.toString(result))); + } + return valid.booleanValue(); + } + + /** + * @return byte array of length 8 (or OUTPUT_LEN) bytes. + */ + private byte[] pdf() + { + // Make Nonce 16 bytes by prepending zeroes. done (see init()) + // one AES invocation is enough for more than one PDF invocation + // number of index bits needed = 1 + // Extract index bits and zero low bits of Nonce + BigInteger Nonce = new BigInteger(1, nonce); + int nlowbitsnum = Nonce.testBit(0) ? 1 : 0; + Nonce = Nonce.clearBit(0); + // Generate subkey, AES and extract indexed substring + IRandom kdf = new UMacGenerator(); + Map map = new HashMap(); + map.put(IBlockCipher.KEY_MATERIAL, K); + map.put(UMacGenerator.INDEX, Integer.valueOf(128)); + kdf.init(map); + byte[] Kp = new byte[KEY_LEN]; + try + { + kdf.nextBytes(Kp, 0, KEY_LEN); + } + catch (IllegalStateException x) + { + x.printStackTrace(System.err); + throw new RuntimeException(String.valueOf(x)); + } + catch (LimitReachedException x) + { + x.printStackTrace(System.err); + throw new RuntimeException(String.valueOf(x)); + } + IBlockCipher aes = CipherFactory.getInstance(Registry.AES_CIPHER); + map.put(IBlockCipher.KEY_MATERIAL, Kp); + try + { + aes.init(map); + } + catch (InvalidKeyException x) + { + x.printStackTrace(System.err); + throw new RuntimeException(String.valueOf(x)); + } + catch (IllegalStateException x) + { + x.printStackTrace(System.err); + throw new RuntimeException(String.valueOf(x)); + } + byte[] T = new byte[16]; + aes.encryptBlock(nonce, 0, T, 0); + byte[] result = new byte[OUTPUT_LEN]; + System.arraycopy(T, nlowbitsnum, result, 0, OUTPUT_LEN); + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/BaseMode.java b/libjava/classpath/gnu/javax/crypto/mode/BaseMode.java new file mode 100644 index 000000000..831dd9664 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/BaseMode.java @@ -0,0 +1,295 @@ +/* BaseMode.java -- + 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.crypto.mode; + +import gnu.java.lang.CPStringBuilder; + +import gnu.javax.crypto.cipher.IBlockCipher; + +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * A basic abstract class to facilitate implementing block cipher modes of + * operations. + */ +public abstract class BaseMode + implements IMode +{ + /** The canonical name prefix of this mode. */ + protected String name; + /** The state indicator of this instance. */ + protected int state; + /** The underlying block cipher implementation. */ + protected IBlockCipher cipher; + /** The block size, in bytes, to operate the underlying block cipher in. */ + protected int cipherBlockSize; + /** The block size, in bytes, in which to operate the mode instance. */ + protected int modeBlockSize; + /** The initialisation vector value. */ + protected byte[] iv; + /** The instance lock. */ + protected Object lock = new Object(); + + /** + * Trivial constructor for use by concrete subclasses. + * + * @param name the canonical name prefix of this mode. + * @param underlyingCipher the implementation of the underlying cipher. + * @param cipherBlockSize the block size, in bytes, in which to operate the + * underlying cipher. + */ + protected BaseMode(String name, IBlockCipher underlyingCipher, + int cipherBlockSize) + { + super(); + + this.name = name; + this.cipher = underlyingCipher; + this.cipherBlockSize = cipherBlockSize; + state = -1; + } + + public void update(byte[] in, int inOffset, byte[] out, int outOffset) + throws IllegalStateException + { + synchronized (lock) + { + switch (state) + { + case ENCRYPTION: + encryptBlock(in, inOffset, out, outOffset); + break; + case DECRYPTION: + decryptBlock(in, inOffset, out, outOffset); + break; + default: + throw new IllegalStateException(); + } + } + } + + public String name() + { + return new CPStringBuilder(name).append('(').append(cipher.name()).append(')') + .toString(); + } + + /** + * Returns the default value, in bytes, of the mode's block size. This value + * is part of the construction arguments passed to the Factory methods in + * {@link ModeFactory}. Unless changed by an invocation of any of the + * init() methods, a Mode instance would operate with + * the same block size as its underlying block cipher. As mentioned earlier, + * the block size of the underlying block cipher itself is specified in one of + * the method(s) available in the factory class. + * + * @return the default value, in bytes, of the mode's block size. + * @see ModeFactory + */ + public int defaultBlockSize() + { + return cipherBlockSize; + } + + /** + * Returns the default value, in bytes, of the underlying block cipher key + * size. + * + * @return the default value, in bytes, of the underlying cipher's key size. + */ + public int defaultKeySize() + { + return cipher.defaultKeySize(); + } + + /** + * Returns an {@link Iterator} over the supported block sizes. Each element + * returned by this object is an {@link Integer}. + *

+ * The default behaviour is to return an iterator with just one value, which + * is that currently configured for the underlying block cipher. Concrete + * implementations may override this behaviour to signal their ability to + * support other values. + * + * @return an {@link Iterator} over the supported block sizes. + */ + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(cipherBlockSize)); + return Collections.unmodifiableList(al).iterator(); + } + + /** + * Returns an {@link Iterator} over the supported underlying block cipher key + * sizes. Each element returned by this object is an instance of + * {@link Integer}. + * + * @return an {@link Iterator} over the supported key sizes. + */ + public Iterator keySizes() + { + return cipher.keySizes(); + } + + public void init(Map attributes) throws InvalidKeyException, + IllegalStateException + { + synchronized (lock) + { + if (state != -1) + throw new IllegalStateException(); + Integer want = (Integer) attributes.get(STATE); + if (want != null) + { + switch (want.intValue()) + { + case ENCRYPTION: + state = ENCRYPTION; + break; + case DECRYPTION: + state = DECRYPTION; + break; + default: + throw new IllegalArgumentException(); + } + } + Integer bs = (Integer) attributes.get(MODE_BLOCK_SIZE); + modeBlockSize = (bs == null ? cipherBlockSize : bs.intValue()); + byte[] iv = (byte[]) attributes.get(IV); + if (iv != null) + this.iv = (byte[]) iv.clone(); + else + this.iv = new byte[modeBlockSize]; + cipher.init(attributes); + setup(); + } + } + + public int currentBlockSize() + { + if (state == -1) + throw new IllegalStateException(); + return modeBlockSize; + } + + public void reset() + { + synchronized (lock) + { + state = -1; + iv = null; + cipher.reset(); + teardown(); + } + } + + public boolean selfTest() + { + int ks; + Iterator bit; + for (Iterator kit = keySizes(); kit.hasNext();) + { + ks = ((Integer) kit.next()).intValue(); + for (bit = blockSizes(); bit.hasNext();) + if (! testSymmetry(ks, ((Integer) bit.next()).intValue())) + return false; + } + return true; + } + + public abstract Object clone(); + + /** The initialisation phase of the concrete mode implementation. */ + public abstract void setup(); + + /** The termination phase of the concrete mode implementation. */ + public abstract void teardown(); + + public abstract void encryptBlock(byte[] in, int i, byte[] out, int o); + + public abstract void decryptBlock(byte[] in, int i, byte[] out, int o); + + private boolean testSymmetry(int ks, int bs) + { + try + { + IMode mode = (IMode) this.clone(); + byte[] iv = new byte[cipherBlockSize]; // all zeroes + byte[] k = new byte[ks]; + int i; + for (i = 0; i < ks; i++) + k[i] = (byte) i; + int blockCount = 5; + int limit = blockCount * bs; + byte[] pt = new byte[limit]; + for (i = 0; i < limit; i++) + pt[i] = (byte) i; + byte[] ct = new byte[limit]; + byte[] cpt = new byte[limit]; + Map map = new HashMap(); + map.put(KEY_MATERIAL, k); + map.put(CIPHER_BLOCK_SIZE, Integer.valueOf(cipherBlockSize)); + map.put(STATE, Integer.valueOf(ENCRYPTION)); + map.put(IV, iv); + map.put(MODE_BLOCK_SIZE, Integer.valueOf(bs)); + mode.reset(); + mode.init(map); + for (i = 0; i < blockCount; i++) + mode.update(pt, i * bs, ct, i * bs); + mode.reset(); + map.put(STATE, Integer.valueOf(DECRYPTION)); + mode.init(map); + for (i = 0; i < blockCount; i++) + mode.update(ct, i * bs, cpt, i * bs); + return Arrays.equals(pt, cpt); + } + catch (Exception x) + { + x.printStackTrace(System.err); + return false; + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/CBC.java b/libjava/classpath/gnu/javax/crypto/mode/CBC.java new file mode 100644 index 000000000..31c445f4e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/CBC.java @@ -0,0 +1,123 @@ +/* CBC.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.mode; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.IBlockCipher; + +/** + * The Cipher Block Chaining mode. This mode introduces feedback into the cipher + * by XORing the previous ciphertext block with the plaintext block before + * encipherment. That is, encrypting looks like this: + * + *

+ *  Ci = EK(Piˆ Ci-1)
+ * 
+ *

+ * Similarly, decrypting is: + *

+ *  Pi = Ci-1 ˆ DK(Ci)
+ * 
+ */ +public class CBC + extends BaseMode + implements Cloneable +{ + /** The last (de|en)crypted block */ + private byte[] lastBlock; + /** An intermediate buffer. */ + private byte[] scratch; + + /** + * Package-private constructor for the factory class. + * + * @param underlyingCipher The cipher implementation. + * @param cipherBlockSize The cipher's block size. + */ + CBC(IBlockCipher underlyingCipher, int cipherBlockSize) + { + super(Registry.CBC_MODE, underlyingCipher, cipherBlockSize); + } + + /** Our constructor for cloning. */ + private CBC(CBC that) + { + this((IBlockCipher) that.cipher.clone(), that.cipherBlockSize); + } + + public Object clone() + { + return new CBC(this); + } + + public void setup() + { + if (modeBlockSize != cipherBlockSize) + throw new IllegalArgumentException(); + scratch = new byte[cipherBlockSize]; + lastBlock = new byte[cipherBlockSize]; + // lastBlock gets initialized to the initialization vector. + for (int i = 0; i < lastBlock.length && i < iv.length; i++) + lastBlock[i] = iv[i]; + } + + public void teardown() + { + lastBlock = null; + scratch = null; + } + + public void encryptBlock(byte[] in, int i, byte[] out, int o) + { + for (int k = 0; k < scratch.length; k++) + scratch[k] = (byte)(lastBlock[k] ^ in[k + i]); + cipher.encryptBlock(scratch, 0, out, o); + System.arraycopy(out, o, lastBlock, 0, cipherBlockSize); + } + + public void decryptBlock(byte[] in, int i, byte[] out, int o) + { + byte[] buf = new byte[cipherBlockSize]; + System.arraycopy(in, i, buf, 0, cipherBlockSize); + cipher.decryptBlock(in, i, scratch, 0); + for (int k = 0; k < scratch.length; k++) + out[o + k] = (byte)(lastBlock[k] ^ scratch[k]); + System.arraycopy(buf, 0, lastBlock, 0, cipherBlockSize); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/CFB.java b/libjava/classpath/gnu/javax/crypto/mode/CFB.java new file mode 100644 index 000000000..c5f06e11c --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/CFB.java @@ -0,0 +1,155 @@ +/* CFB.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.mode; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.IBlockCipher; + +/** + * The cipher feedback mode. CFB mode is a stream mode that operates on s + * bit blocks, where 1 <= s <= b, if b is the + * underlying cipher's block size. Encryption is: + *
+ *  I[1] = IV
+ *  I[j] = LSB(b-s, I[j-1]) | C[j-1]   for j = 2...n
+ *  O[j] = CIPH(K, I[j])               for j = 1,2...n
+ *  C[j] = P[j] ˆ MSB(s, O[j])         for j = 1,2...n
+ * 
+ *

+ * And decryption is: + *

+ *  I[1] = IV
+ *  I[j] = LSB(b-s, I[j-1]) | C[j-1]   for j = 2...n
+ *  O[j] = CIPH(K, I[j])               for j = 1,2...n
+ *  P[j] = C[j] ˆ MSB(s, O[j])         for j = 1,2...n
+ * 
+ *

+ * CFB mode requires an initialization vector, which need not be kept secret. + *

+ * References: + *

    + *
  1. Bruce Schneier, Applied Cryptography: Protocols, Algorithms, and + * Source Code in C, Second Edition. (1996 John Wiley and Sons) ISBN + * 0-471-11709-9.
  2. + *
  3. + * Recommendation for Block Cipher Modes of Operation Methods and Techniques, + * Morris Dworkin.
  4. + *
+ */ +public class CFB + extends BaseMode +{ + /** The shift register, the input block to the block cipher. */ + private byte[] shiftRegister; + /** The output block from the block cipher. */ + private byte[] scratch; + + /** + * Package-private constructor for the factory class. + * + * @param underlyingCipher The cipher implementation. + * @param cipherBlockSize The cipher's block size. + */ + CFB(IBlockCipher underlyingCipher, int cipherBlockSize) + { + super(Registry.CFB_MODE, underlyingCipher, cipherBlockSize); + } + + /** + * Cloneing constructor. + * + * @param that The instance being cloned. + */ + private CFB(CFB that) + { + this((IBlockCipher) that.cipher.clone(), that.cipherBlockSize); + } + + public Object clone() + { + return new CFB(this); + } + + public void setup() + { + if (modeBlockSize > cipherBlockSize) + throw new IllegalArgumentException( + "CFB block size cannot be larger than the cipher block size"); + shiftRegister = new byte[cipherBlockSize]; + scratch = new byte[cipherBlockSize]; + System.arraycopy(iv, 0, + shiftRegister, 0, + Math.min(iv.length, cipherBlockSize)); + } + + public void teardown() + { + if (shiftRegister != null) + for (int i = 0; i < shiftRegister.length; i++) + shiftRegister[i] = 0; + shiftRegister = null; + } + + public void encryptBlock(byte[] in, int inOffset, byte[] out, int outOffset) + { + cipher.encryptBlock(shiftRegister, 0, scratch, 0); + for (int i = 0; i < modeBlockSize; i++) + out[outOffset + i] = (byte)(in[inOffset + i] ^ scratch[i]); + System.arraycopy(shiftRegister, modeBlockSize, + shiftRegister, 0, + cipherBlockSize - modeBlockSize); + System.arraycopy(out, outOffset, + shiftRegister, cipherBlockSize - modeBlockSize, + modeBlockSize); + } + + public void decryptBlock(byte[] in, int inOffset, byte[] out, int outOffset) + { + cipher.encryptBlock(shiftRegister, 0, scratch, 0); + for (int i = 0; i < modeBlockSize; i++) + out[outOffset + i] = (byte)(in[inOffset + i] ^ scratch[i]); + System.arraycopy(shiftRegister, modeBlockSize, + shiftRegister, 0, + cipherBlockSize - modeBlockSize); + System.arraycopy(in, inOffset, + shiftRegister, cipherBlockSize - modeBlockSize, + modeBlockSize); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/CTR.java b/libjava/classpath/gnu/javax/crypto/mode/CTR.java new file mode 100644 index 000000000..56ea58c25 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/CTR.java @@ -0,0 +1,168 @@ +/* CTR.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.mode; + +import gnu.java.security.Registry; +import gnu.java.security.util.Sequence; +import gnu.javax.crypto.cipher.IBlockCipher; + +import java.util.Arrays; +import java.util.Iterator; + +/** + * The implementation of the Counter Mode. + *

+ * The algorithm steps are formally described as follows: + * + *

+ *     CTR Encryption: O[j] = E(K)(T[j]); for j = 1, 2...n;
+ *                     C[j] = P[j] ˆ O[j]; for j = 1, 2...n.
+ *     CTR Decryption: O[j] = E(K)(T[j]); for j = 1, 2...n;
+ *                     P[j] = C[j] ˆ O[j]; for j = 1, 2...n.
+ * 
+ * + *

+ * where P is the plaintext, C is the ciphertext, + * E(K) is the underlying block cipher encryption function + * parametrised with the session key K, and T is + * the Counter. + *

+ * This implementation, uses a standard incrementing function with a step of 1, + * and an initial value similar to that described in the NIST document. + *

+ * References: + *

    + *
  1. + * Recommendation for Block Cipher Modes of Operation Methods and Techniques, + * Morris Dworkin.
  2. + *
+ */ +public class CTR + extends BaseMode + implements Cloneable +{ + private int off; + private byte[] counter, enc; + + /** + * Trivial package-private constructor for use by the Factory class. + * + * @param underlyingCipher the underlying cipher implementation. + * @param cipherBlockSize the underlying cipher block size to use. + */ + CTR(IBlockCipher underlyingCipher, int cipherBlockSize) + { + super(Registry.CTR_MODE, underlyingCipher, cipherBlockSize); + } + + /** + * Private constructor for cloning purposes. + * + * @param that the instance to clone. + */ + private CTR(CTR that) + { + this((IBlockCipher) that.cipher.clone(), that.cipherBlockSize); + } + + public Object clone() + { + return new CTR(this); + } + + public void setup() + { + if (modeBlockSize > cipherBlockSize) + throw new IllegalArgumentException("mode size exceeds cipher block size"); + off = 0; + counter = new byte[cipherBlockSize]; + int i = cipherBlockSize - 1; + int j = iv.length - 1; + while (i >= 0 && j >= 0) + counter[i--] = iv[j--]; + enc = new byte[cipherBlockSize]; + cipher.encryptBlock(counter, 0, enc, 0); + } + + public void teardown() + { + if (counter != null) + Arrays.fill(counter, (byte) 0); + if (enc != null) + Arrays.fill(enc, (byte) 0); + } + + public void encryptBlock(byte[] in, int i, byte[] out, int o) + { + ctr(in, i, out, o); + } + + public void decryptBlock(byte[] in, int i, byte[] out, int o) + { + ctr(in, i, out, o); + } + + public Iterator blockSizes() + { + return new Sequence(1, cipherBlockSize).iterator(); + } + + private void ctr(byte[] in, int inOffset, byte[] out, int outOffset) + { + for (int i = 0; i < modeBlockSize; i++) + { + out[outOffset++] = (byte)(in[inOffset++] ^ enc[off++]); + if (off == cipherBlockSize) + { + int j; + for (j = cipherBlockSize - 1; j >= 0; j--) + { + counter[j]++; + if ((counter[j] & 0xFF) != 0) + break; + } + if (j == 0) + counter[cipherBlockSize - 1]++; + off = 0; + cipher.encryptBlock(counter, 0, enc, 0); + } + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/EAX.java b/libjava/classpath/gnu/javax/crypto/mode/EAX.java new file mode 100644 index 000000000..b3e4a6a4e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/EAX.java @@ -0,0 +1,289 @@ +/* EAX.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.mode; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; + +import java.security.InvalidKeyException; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * A conventional two-pass authenticated-encrypted mode, EAX. EAX is a + * Authenticated Encryption with Additional Data (AEAD) scheme, + * which provides protection and authentication for the message, and provides + * authentication of an (optional) header. EAX is composed of the counter mode + * (CTR) and the one-key CBC MAC (OMAC). + *

+ * This class makes full use of the {@link IAuthenticatedMode} interface, that + * is, all methods of both {@link IMode} and {@link IMac} can be used as + * specified in the {@link IAuthenticatedMode} interface. + *

+ * References: + *

    + *
  1. M. Bellare, P. Rogaway, and D. Wagner; A + * Conventional Authenticated-Encryption Mode.
  2. + *
+ */ +public class EAX + implements IAuthenticatedMode +{ + /** The tag size, in bytes. */ + private int tagSize; + /** The nonce OMAC instance. */ + private IMac nonceOmac; + /** The header OMAC instance. */ + private IMac headerOmac; + /** The message OMAC instance. */ + private IMac msgOmac; + /** The CTR instance. */ + private IMode ctr; + /** The direction state (encrypting or decrypting). */ + private int state; + /** Whether we're initialized or not. */ + private boolean init; + /** The cipher block size. */ + private int cipherBlockSize; + /** The cipher. */ + private IBlockCipher cipher; + /** The [t]_n array. */ + private byte[] t_n; + private static boolean valid = false; + + public EAX(IBlockCipher cipher, int cipherBlockSize) + { + this.cipher = cipher; + this.cipherBlockSize = cipherBlockSize; + String name = cipher.name(); + int i = name.indexOf('-'); + if (i >= 0) + name = name.substring(0, i); + String omacname = Registry.OMAC_PREFIX + name; + nonceOmac = MacFactory.getInstance(omacname); + headerOmac = MacFactory.getInstance(omacname); + msgOmac = MacFactory.getInstance(omacname); + ctr = ModeFactory.getInstance(Registry.CTR_MODE, cipher, cipherBlockSize); + t_n = new byte[cipherBlockSize]; + init = false; + } + + public Object clone() + { + return new EAX((IBlockCipher) cipher.clone(), cipherBlockSize); + } + + public String name() + { + return Registry.EAX_MODE + "(" + cipher.name() + ")"; + } + + public int defaultBlockSize() + { + return ctr.defaultBlockSize(); + } + + public int defaultKeySize() + { + return ctr.defaultKeySize(); + } + + public Iterator blockSizes() + { + return ctr.blockSizes(); + } + + public Iterator keySizes() + { + return ctr.keySizes(); + } + + public void init(Map attrib) throws InvalidKeyException + { + byte[] nonce = (byte[]) attrib.get(IV); + if (nonce == null) + throw new IllegalArgumentException("no nonce provided"); + byte[] key = (byte[]) attrib.get(KEY_MATERIAL); + if (key == null) + throw new IllegalArgumentException("no key provided"); + + Arrays.fill(t_n, (byte) 0); + nonceOmac.reset(); + nonceOmac.init(Collections.singletonMap(MAC_KEY_MATERIAL, key)); + nonceOmac.update(t_n, 0, t_n.length); + nonceOmac.update(nonce, 0, nonce.length); + byte[] N = nonceOmac.digest(); + nonceOmac.reset(); + nonceOmac.update(t_n, 0, t_n.length); + nonceOmac.update(nonce, 0, nonce.length); + t_n[t_n.length - 1] = 1; + headerOmac.reset(); + headerOmac.init(Collections.singletonMap(MAC_KEY_MATERIAL, key)); + headerOmac.update(t_n, 0, t_n.length); + t_n[t_n.length - 1] = 2; + msgOmac.reset(); + msgOmac.init(Collections.singletonMap(MAC_KEY_MATERIAL, key)); + msgOmac.update(t_n, 0, t_n.length); + Integer modeSize = (Integer) attrib.get(MODE_BLOCK_SIZE); + if (modeSize == null) + modeSize = Integer.valueOf(cipherBlockSize); + HashMap ctrAttr = new HashMap(); + ctrAttr.put(KEY_MATERIAL, key); + ctrAttr.put(IV, N); + ctrAttr.put(STATE, Integer.valueOf(ENCRYPTION)); + ctrAttr.put(MODE_BLOCK_SIZE, modeSize); + ctr.reset(); + ctr.init(ctrAttr); + Integer st = (Integer) attrib.get(STATE); + if (st != null) + { + state = st.intValue(); + if (state != ENCRYPTION && state != DECRYPTION) + throw new IllegalArgumentException("invalid state"); + } + else + state = ENCRYPTION; + + Integer ts = (Integer) attrib.get(TRUNCATED_SIZE); + if (ts != null) + tagSize = ts.intValue(); + else + tagSize = cipherBlockSize; + if (tagSize < 0 || tagSize > cipherBlockSize) + throw new IllegalArgumentException("tag size out of range"); + init = true; + } + + public int currentBlockSize() + { + return ctr.currentBlockSize(); + } + + public void encryptBlock(byte[] in, int inOff, byte[] out, int outOff) + { + if (! init) + throw new IllegalStateException("not initialized"); + if (state != ENCRYPTION) + throw new IllegalStateException("not encrypting"); + ctr.update(in, inOff, out, outOff); + msgOmac.update(out, outOff, ctr.currentBlockSize()); + } + + public void decryptBlock(byte[] in, int inOff, byte[] out, int outOff) + { + if (! init) + throw new IllegalStateException("not initialized"); + if (state != DECRYPTION) + throw new IllegalStateException("not decrypting"); + msgOmac.update(in, inOff, ctr.currentBlockSize()); + ctr.update(in, inOff, out, outOff); + } + + public void update(byte[] in, int inOff, byte[] out, int outOff) + { + switch (state) + { + case ENCRYPTION: + encryptBlock(in, inOff, out, outOff); + break; + case DECRYPTION: + decryptBlock(in, inOff, out, outOff); + break; + default: + throw new IllegalStateException("impossible state " + state); + } + } + + public void reset() + { + nonceOmac.reset(); + headerOmac.reset(); + msgOmac.reset(); + ctr.reset(); + } + + public boolean selfTest() + { + return true; // XXX + } + + public int macSize() + { + return tagSize; + } + + public byte[] digest() + { + byte[] tag = new byte[tagSize]; + digest(tag, 0); + return tag; + } + + public void digest(byte[] out, int outOffset) + { + if (outOffset < 0 || outOffset + tagSize > out.length) + throw new IndexOutOfBoundsException(); + byte[] N = nonceOmac.digest(); + byte[] H = headerOmac.digest(); + byte[] M = msgOmac.digest(); + for (int i = 0; i < tagSize; i++) + out[outOffset + i] = (byte)(N[i] ^ H[i] ^ M[i]); + reset(); + } + + public void update(byte b) + { + if (! init) + throw new IllegalStateException("not initialized"); + headerOmac.update(b); + } + + public void update(byte[] buf, int off, int len) + { + if (! init) + throw new IllegalStateException("not initialized"); + headerOmac.update(buf, off, len); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/ECB.java b/libjava/classpath/gnu/javax/crypto/mode/ECB.java new file mode 100644 index 000000000..7e02b0187 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/ECB.java @@ -0,0 +1,121 @@ +/* ECB.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.mode; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.IBlockCipher; + +/** + * The implementation of the Electronic Codebook mode. + *

+ * The Electronic Codebook (ECB) mode is a confidentiality mode that is defined + * as follows: + *

+ *

+ * In ECB encryption, the forward cipher function is applied directly, and + * independently, to each block of the plaintext. The resulting sequence of + * output blocks is the ciphertext. + *

+ * In ECB decryption, the inverse cipher function is applied directly, and + * independently, to each block of the ciphertext. The resulting sequence of + * output blocks is the plaintext. + *

+ * References: + *

    + *
  1. + * Recommendation for Block Cipher Modes of Operation Methods and Techniques, + * Morris Dworkin.
  2. + *
+ */ +public class ECB + extends BaseMode + implements Cloneable +{ + /** + * Trivial package-private constructor for use by the Factory class. + * + * @param underlyingCipher the underlying cipher implementation. + * @param cipherBlockSize the underlying cipher block size to use. + */ + ECB(IBlockCipher underlyingCipher, int cipherBlockSize) + { + super(Registry.ECB_MODE, underlyingCipher, cipherBlockSize); + } + + /** + * Private constructor for cloning purposes. + * + * @param that the mode to clone. + */ + private ECB(ECB that) + { + this((IBlockCipher) that.cipher.clone(), that.cipherBlockSize); + } + + public Object clone() + { + return new ECB(this); + } + + public void setup() + { + if (modeBlockSize != cipherBlockSize) + throw new IllegalArgumentException(IMode.MODE_BLOCK_SIZE); + } + + public void teardown() + { + } + + public void encryptBlock(byte[] in, int i, byte[] out, int o) + { + cipher.encryptBlock(in, i, out, o); + } + + public void decryptBlock(byte[] in, int i, byte[] out, int o) + { + cipher.decryptBlock(in, i, out, o); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/IAuthenticatedMode.java b/libjava/classpath/gnu/javax/crypto/mode/IAuthenticatedMode.java new file mode 100644 index 000000000..51a5547f2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/IAuthenticatedMode.java @@ -0,0 +1,56 @@ +/* IAuthenticatedMode.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.mode; + +import gnu.javax.crypto.mac.IMac; + +/** + * The interface for encryption modes that also produce a message authentication + * tag. + *

+ * This interface is merely the conjuction of the {@link IMode} and {@link IMac} + * interfaces. Encryption and decryption is done via the + * {@link IMode#update(byte[],int,byte[],int)} method, tag generation is done + * via the {@link IMac#digest()} method, and header updating (if supported by + * the mode) is done via the {@link IMac#update(byte[],int,int)} method. + */ +public interface IAuthenticatedMode + extends IMode, IMac +{ +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/ICM.java b/libjava/classpath/gnu/javax/crypto/mode/ICM.java new file mode 100644 index 000000000..a4737bcdf --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/ICM.java @@ -0,0 +1,181 @@ +/* ICM.java -- + 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.crypto.mode; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.IBlockCipher; + +import java.math.BigInteger; + +/** + * An implementation of David McGrew Integer Counter Mode (ICM) as an + * {@link IMode}. + *

+ * ICM is a way to define a pseudorandom keystream generator using a block + * cipher. The keystream can be used for additive encryption, key derivation, or + * any other application requiring pseudorandom data. In the case of this class, + * it is used as additive encryption, XOR-ing the keystream with the input text + * --for both encryption and decryption. + *

+ * In ICM, the keystream is logically broken into segments. Each segment is + * identified with a segment index, and the segments have equal lengths. This + * segmentation makes ICM especially appropriate for securing packet-based + * protocols. ICM also allows a variety of configurations based, among other + * things, on two parameters: the block index length and the segment + * index length. A constraint on those two values exists: The sum of + * segment index length and block index length must not + * half the block size of the underlying cipher. This requirement + * protects the ICM keystream generator from potentially failing to be + * pseudorandom. + *

+ * For simplicity, this implementation, fixes these two values to the following: + *

+ *

+ * For a 128-bit block cipher, the above values imply a maximum keystream length + * of 295,147,905,179,352,825,856 octets, since in ICM, each segment must not + * exceed the value + * (256 ^ block index length) * block length + * octets. + *

+ * Finally, for this implementation of the ICM, the IV placeholder will be used + * to pass the value of the Offset in the keystream segment. + *

+ * References: + *

    + *
  1. + * Integer Counter Mode, David A. McGrew.
  2. + *
+ */ +public class ICM + extends BaseMode + implements Cloneable +{ + /** The integer value 256 as a BigInteger. */ + private static final BigInteger TWO_FIFTY_SIX = new BigInteger("256"); + /** Maximum number of blocks per segment. */ + private BigInteger maxBlocksPerSegment; + /** A work constant. */ + private BigInteger counterRange; + /** The initial counter for a given keystream segment. */ + private BigInteger C0; + /** The index of the next block for a given keystream segment. */ + private BigInteger blockNdx; + + /** + * Trivial package-private constructor for use by the Factory class. + * + * @param underlyingCipher the underlying cipher implementation. + * @param cipherBlockSize the underlying cipher block size to use. + */ + ICM(IBlockCipher underlyingCipher, int cipherBlockSize) + { + super(Registry.ICM_MODE, underlyingCipher, cipherBlockSize); + } + + /** + * Private constructor for cloning purposes. + * + * @param that the instance to clone. + */ + private ICM(ICM that) + { + this((IBlockCipher) that.cipher.clone(), that.cipherBlockSize); + } + + public Object clone() + { + return new ICM(this); + } + + public void setup() + { + if (modeBlockSize != cipherBlockSize) + throw new IllegalArgumentException(); + counterRange = TWO_FIFTY_SIX.pow(cipherBlockSize); + maxBlocksPerSegment = TWO_FIFTY_SIX.pow(cipherBlockSize / 2); + BigInteger r = new BigInteger(1, iv); + C0 = maxBlocksPerSegment.add(r).modPow(BigInteger.ONE, counterRange); + blockNdx = BigInteger.ZERO; + } + + public void teardown() + { + counterRange = null; + maxBlocksPerSegment = null; + C0 = null; + blockNdx = null; + } + + public void encryptBlock(byte[] in, int i, byte[] out, int o) + { + icm(in, i, out, o); + } + + public void decryptBlock(byte[] in, int i, byte[] out, int o) + { + icm(in, i, out, o); + } + + private void icm(byte[] in, int inOffset, byte[] out, int outOffset) + { + if (blockNdx.compareTo(maxBlocksPerSegment) >= 0) + throw new RuntimeException("Maximum blocks for segment reached"); + BigInteger Ci = C0.add(blockNdx).modPow(BigInteger.ONE, counterRange); + byte[] result = Ci.toByteArray(); + int limit = result.length; + int ndx = 0; + if (limit < cipherBlockSize) + { + byte[] data = new byte[cipherBlockSize]; + System.arraycopy(result, 0, data, cipherBlockSize - limit, limit); + result = data; + } + else if (limit > cipherBlockSize) + ndx = limit - cipherBlockSize; + + cipher.encryptBlock(result, ndx, result, ndx); + blockNdx = blockNdx.add(BigInteger.ONE); // increment blockNdx + for (int i = 0; i < modeBlockSize; i++) // xor result with input block + out[outOffset++] = (byte)(in[inOffset++] ^ result[ndx++]); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/IMode.java b/libjava/classpath/gnu/javax/crypto/mode/IMode.java new file mode 100644 index 000000000..72c99ba73 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/IMode.java @@ -0,0 +1,123 @@ +/* IMode.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.mode; + +import gnu.javax.crypto.cipher.IBlockCipher; + +/** + * The basic visible methods of any block cipher mode. + *

+ * Block ciphers encrypt plaintext in fixed size n-bit blocks. For messages + * larger than n bits, the simplest approach is to segment the message into + * n-bit blocks and process (encrypt and/or decrypt) each one separately + * (Electronic Codebook or ECB mode). But this approach has disadvantages in + * most applications. The block cipher modes of operations are one way of + * working around those disadvantages. + *

+ * A Mode always employs an underlying block cipher for processing its + * input. For all intents and purposes, a Mode appears to behave as any + * other block cipher with the following differences: + *

+ *

+ * Possible additional initialisation values for an instance of that type are: + *

+ */ +public interface IMode + extends IBlockCipher +{ + /** + * Property name of the state in which to operate this mode. The value + * associated to this property name is taken to be an {@link Integer} which + * value is either ENCRYPTION or DECRYPTION. + */ + String STATE = "gnu.crypto.mode.state"; + /** + * Property name of the block size in which to operate this mode. The value + * associated with this property name is taken to be an {@link Integer}. If + * it is not specified, the value of the block size of the underlying block + * cipher, used to construct the mode instance, shall be used. + */ + String MODE_BLOCK_SIZE = "gnu.crypto.mode.block.size"; + /** + * Property name of the initialisation vector to use, if required, with this + * instance. The value associated with this property name is taken to be a + * byte array. If the concrete instance needs such a parameter, and it has not + * been specified as part of the initialissation parameters, an all-zero byte + * array of the appropriate size shall be used. + */ + String IV = "gnu.crypto.mode.iv"; + /** Constant indicating the instance is being used for encryption. */ + int ENCRYPTION = 1; + /** Constant indicating the instance is being used for decryption. */ + int DECRYPTION = 2; + + /** + * A convenience method. Effectively invokes the encryptBlock() + * or decryptBlock() method depending on the operational state + * of the instance. + * + * @param in the plaintext. + * @param inOffset index of in from which to start considering + * data. + * @param out the ciphertext. + * @param outOffset index of out from which to store result. + * @exception IllegalStateException if the instance is not initialised. + */ + void update(byte[] in, int inOffset, byte[] out, int outOffset) + throws IllegalStateException; +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/ModeFactory.java b/libjava/classpath/gnu/javax/crypto/mode/ModeFactory.java new file mode 100644 index 000000000..c1108ea11 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/ModeFactory.java @@ -0,0 +1,151 @@ +/* ModeFactory.java -- + Copyright (C) 2001, 2002, 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.mode; + +import gnu.java.security.Registry; + +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +/** + * A Factory to instantiate block cipher modes of operations. + */ +public class ModeFactory + implements Registry +{ + private static Set names; + + /** Trivial constructor to enforce Singleton pattern. */ + private ModeFactory() + { + super(); + } + + /** + * Returns an instance of a block cipher mode of operations given its name and + * characteristics of the underlying block cipher. + * + * @param mode the case-insensitive name of the mode of operations. + * @param cipher the case-insensitive name of the block cipher. + * @param cipherBlockSize the block size, in bytes, of the underlying cipher. + * @return an instance of the block cipher algorithm, operating in a given + * mode of operations, or null if none found. + * @exception InternalError if either the mode or the underlying block cipher + * implementation does not pass its self-test. + */ + public static IMode getInstance(String mode, String cipher, + int cipherBlockSize) + { + if (mode == null || cipher == null) + return null; + + mode = mode.trim(); + cipher = cipher.trim(); + IBlockCipher cipherImpl = CipherFactory.getInstance(cipher); + if (cipherImpl == null) + return null; + + return getInstance(mode, cipherImpl, cipherBlockSize); + } + + public static IMode getInstance(String mode, IBlockCipher cipher, + int cipherBlockSize) + { + // ensure that cipherBlockSize is valid for the chosen underlying cipher + boolean ok = false; + for (Iterator it = cipher.blockSizes(); it.hasNext();) + { + ok = (cipherBlockSize == ((Integer) it.next()).intValue()); + if (ok) + break; + } + if (! ok) + throw new IllegalArgumentException("cipherBlockSize"); + IMode result = null; + if (mode.equalsIgnoreCase(ECB_MODE)) + result = new ECB(cipher, cipherBlockSize); + else if (mode.equalsIgnoreCase(CTR_MODE)) + result = new CTR(cipher, cipherBlockSize); + else if (mode.equalsIgnoreCase(ICM_MODE)) + result = new ICM(cipher, cipherBlockSize); + else if (mode.equalsIgnoreCase(OFB_MODE)) + result = new OFB(cipher, cipherBlockSize); + else if (mode.equalsIgnoreCase(CBC_MODE)) + result = new CBC(cipher, cipherBlockSize); + else if (mode.equalsIgnoreCase(CFB_MODE)) + result = new CFB(cipher, cipherBlockSize); + else if (mode.equalsIgnoreCase(EAX_MODE)) + result = new EAX(cipher, cipherBlockSize); + + if (result != null && ! result.selfTest()) + throw new InternalError(result.name()); + + return result; + } + + /** + * Returns a {@link Set} of names of mode supported by this Factory. + * + * @return a {@link Set} of mode names (Strings). + */ + public static final Set getNames() + { + synchronized (ModeFactory.class) + { + if (names == null) + { + HashSet hs = new HashSet(); + hs.add(ECB_MODE); + hs.add(CTR_MODE); + hs.add(ICM_MODE); + hs.add(OFB_MODE); + hs.add(CBC_MODE); + hs.add(CFB_MODE); + hs.add(EAX_MODE); + names = Collections.unmodifiableSet(hs); + } + } + return names; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/OFB.java b/libjava/classpath/gnu/javax/crypto/mode/OFB.java new file mode 100644 index 000000000..087f99132 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/OFB.java @@ -0,0 +1,174 @@ +/* OFB.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.mode; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.IBlockCipher; + +/** + * The Output Feedback (OFB) mode is a confidentiality mode that requires a + * unique IV for every message that is ever encrypted under the + * given key. The OFB mode is defined as follows: + * + *

+ * In OFB encryption, the IV is transformed by the forward cipher + * function to produce the first output block. The first output block is + * exclusive-ORed with the first plaintext block to produce the first ciphertext + * block. The first output block is then transformed by the forward cipher + * function to produce the second output block. The second output block is + * exclusive-ORed with the second plaintext block to produce the second + * ciphertext block, and the second output block is transformed by the forward + * cipher function to produce the third output block. Thus, the successive + * output blocks are produced from enciphering the previous output blocks, and + * the output blocks are exclusive-ORed with the corresponding plaintext blocks + * to produce the ciphertext blocks. + *

+ * In OFB decryption, the IV is transformed by the forward cipher + * function to produce the first output block. The first output block is + * exclusive-ORed with the first ciphertext block to recover the first plaintext + * block. The first output block is then transformed by the forward cipher + * function to produce the second output block. The second output block is + * exclusive-ORed with the second ciphertext block to produce the second + * plaintext block, and the second output block is also transformed by the + * forward cipher function to produce the third output block. Thus, the + * successive output blocks are produced from enciphering the previous output + * blocks, and the output blocks are exclusive-ORed with the corresponding + * ciphertext blocks to recover the plaintext blocks. + *

+ * In both OFB encryption and OFB decryption, each forward cipher function + * (except the first) depends on the results of the previous forward cipher + * function; therefore, multiple forward cipher functions cannot be performed in + * parallel. However, if the IV is known, the output blocks can + * be generated prior to the availability of the plaintext or ciphertext data. + *

+ * The OFB mode requires a unique IV for every message that is + * ever encrypted under the given key. If, contrary to this requirement, the + * same IV is used for the encryption of more than one message, + * then the confidentiality of those messages may be compromised. In particular, + * if a plaintext block of any of these messages is known, say, the jth + * plaintext block, then the jth output of the forward cipher + * function can be determined easily from the jth ciphertext block + * of the message. This information allows the jth plaintext block + * of any other message that is encrypted using the same IV to be + * easily recovered from the jth ciphertext block of that message. + *

+ * Confidentiality may similarly be compromised if any of the input blocks to + * the forward cipher function for the encryption of a message is used as the + * IV for the encryption of another message under the given key. + *

+ * References: + *

    + *
  1. + * Recommendation for Block Cipher Modes of Operation Methods and Techniques, + * Morris Dworkin.
  2. + *
+ */ +public class OFB + extends BaseMode + implements Cloneable +{ + private byte[] outputBlock; + + /** + * Trivial package-private constructor for use by the Factory class. + * + * @param underlyingCipher the underlying cipher implementation. + * @param cipherBlockSize the underlying cipher block size to use. + */ + OFB(IBlockCipher underlyingCipher, int cipherBlockSize) + { + super(Registry.OFB_MODE, underlyingCipher, cipherBlockSize); + } + + /** + * Private constructor for cloning purposes. + * + * @param that the mode to clone. + */ + private OFB(OFB that) + { + this((IBlockCipher) that.cipher.clone(), that.cipherBlockSize); + } + + public Object clone() + { + return new OFB(this); + } + + public void setup() + { + if (modeBlockSize != cipherBlockSize) + throw new IllegalArgumentException(IMode.MODE_BLOCK_SIZE); + outputBlock = (byte[]) iv.clone(); + } + + public void teardown() + { + } + + public void encryptBlock(byte[] in, int i, byte[] out, int o) + { + cipher.encryptBlock(outputBlock, 0, outputBlock, 0); + for (int j = 0; j < cipherBlockSize;) + out[o++] = (byte)(in[i++] ^ outputBlock[j++]); + } + + public void decryptBlock(byte[] in, int i, byte[] out, int o) + { + this.encryptBlock(in, i, out, o); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/pad/BasePad.java b/libjava/classpath/gnu/javax/crypto/pad/BasePad.java new file mode 100644 index 000000000..feeaca2f0 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/pad/BasePad.java @@ -0,0 +1,193 @@ +/* BasePad.java -- + 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.crypto.pad; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.Configuration; + +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * An abstract class to facilitate implementing padding algorithms. + */ +public abstract class BasePad + implements IPad +{ + private static final Logger log = Logger.getLogger(BasePad.class.getName()); + /** The canonical name prefix of the padding algorithm. */ + protected String name; + /** The block size, in bytes, for this instance. */ + protected int blockSize; + + /** Trivial constructor for use by concrete subclasses. */ + protected BasePad(final String name) + { + super(); + + this.name = name; + blockSize = -1; + } + + public String name() + { + final CPStringBuilder sb = new CPStringBuilder(name); + if (blockSize != -1) + sb.append('-').append(String.valueOf(8 * blockSize)); + return sb.toString(); + } + + public void init(final int bs) throws IllegalStateException + { + if (blockSize != -1) + throw new IllegalStateException(); + blockSize = bs; + setup(); + } + + /** + * Initialises the algorithm with designated attributes. Names, valid and/or + * recognisable by all concrete implementations are described in {@link IPad} + * class documentation. Other algorithm-specific attributes MUST be documented + * in the implementation class of that padding algorithm. + *

+ * For compatibility reasons, this method is not declared abstract. + * Furthermore, and unless overridden, the default implementation will throw + * an {@link UnsupportedOperationException}. Concrete padding algorithms MUST + * override this method if they wish to offer an initialisation method that + * allows for other than the padding block size parameter to be specified. + * + * @param attributes a set of name-value pairs that describes the desired + * future behaviour of this instance. + * @exception IllegalStateException if the instance is already initialised. + * @exception IllegalArgumentException if the block size value is invalid. + */ + public void init(Map attributes) throws IllegalStateException + { + throw new UnsupportedOperationException(); + } + + public void reset() + { + blockSize = -1; + } + + /** + * A default implementation of a correctness test that exercises the padder + * implementation, using block sizes varying from 2 to 256 bytes. + * + * @return true if the concrete implementation correctly unpads + * what it pads for all tested block sizes. Returns false + * if the test fails for any block size. + */ + public boolean selfTest() + { + final byte[] in = new byte[1024]; + for (int bs = 2; bs < 256; bs++) + if (! test1BlockSize(bs, in)) + return false; + return true; + } + + /** + * The basic symmetric test for a padder given a specific block size. + *

+ * The code ensures that the implementation is capable of unpadding what it + * pads. + * + * @param size the block size to test. + * @param buffer a work buffer. It is exposed as an argument for this method + * to reduce un-necessary object allocations. + * @return true if the test passes; false + * otherwise. + */ + protected boolean test1BlockSize(int size, byte[] buffer) + { + byte[] padBytes; + final int offset = 5; + final int limit = buffer.length; + this.init(size); + for (int i = 0; i < limit - offset - blockSize; i++) + { + padBytes = pad(buffer, offset, i); + if (((i + padBytes.length) % blockSize) != 0) + { + if (Configuration.DEBUG) + log.log(Level.SEVERE, + "Length of padded text MUST be a multiple of " + + blockSize, new RuntimeException(name())); + return false; + } + System.arraycopy(padBytes, 0, buffer, offset + i, padBytes.length); + try + { + if (padBytes.length != unpad(buffer, offset, i + padBytes.length)) + { + if (Configuration.DEBUG) + log.log(Level.SEVERE, + "IPad [" + name() + "] failed symmetric operation", + new RuntimeException(name())); + return false; + } + } + catch (WrongPaddingException x) + { + if (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "test1BlockSize", x); + return false; + } + } + this.reset(); + return true; + } + + /** + * If any additional checks or resource setup must be done by the subclass, + * then this is the hook for it. This method will be called before the + * {@link #init(int)} method returns. + */ + public abstract void setup(); + + public abstract byte[] pad(byte[] in, int off, int len); + + public abstract int unpad(byte[] in, int off, int len) + throws WrongPaddingException; +} diff --git a/libjava/classpath/gnu/javax/crypto/pad/IPad.java b/libjava/classpath/gnu/javax/crypto/pad/IPad.java new file mode 100644 index 000000000..f5160e078 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/pad/IPad.java @@ -0,0 +1,127 @@ +/* IPad.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.pad; + +import java.util.Map; + +/** + * The basic visible methods, and attribute names, of every padding algorithm. + *

+ * Padding algorithms serve to pad and unpad byte arrays usually + * as the last step in an encryption or respectively a decryption + * operation. Their input buffers are usually those processed by instances of + * {@link gnu.javax.crypto.mode.IMode} and/or + * {@link gnu.javax.crypto.cipher.IBlockCipher}. + */ +public interface IPad +{ + /** + * Property name of the block size in which to operate the padding algorithm. + * The value associated with this property name is taken to be a positive + * {@link Integer} greater than zero. + */ + String PADDING_BLOCK_SIZE = "gnu.crypto.pad.block.size"; + + /** @return the canonical name of this instance. */ + String name(); + + /** + * Initialises the padding scheme with a designated block size. + * + * @param bs the designated block size. + * @exception IllegalStateException if the instance is already initialised. + * @exception IllegalArgumentException if the block size value is invalid. + */ + void init(int bs) throws IllegalStateException; + + /** + * Initialises the algorithm with designated attributes. Names, valid and/or + * recognisable by all concrete implementations are described in the class + * documentation above. Other algorithm-specific attributes MUST be documented + * in the implementation class of that padding algorithm. + * + * @param attributes a set of name-value pairs that describes the desired + * future behaviour of this instance. + * @exception IllegalStateException if the instance is already initialised. + * @exception IllegalArgumentException if the block size value is invalid. + */ + void init(Map attributes) throws IllegalStateException; + + /** + * Returns the byte sequence that should be appended to the designated input. + * + * @param in the input buffer containing the bytes to pad. + * @param offset the starting index of meaningful data in in. + * @param length the number of meaningful bytes in in. + * @return the possibly 0-byte long sequence to be appended to the designated + * input. + */ + byte[] pad(byte[] in, int offset, int length); + + /** + * Returns the number of bytes to discard from a designated input buffer. + * + * @param in the input buffer containing the bytes to unpad. + * @param offset the starting index of meaningful data in in. + * @param length the number of meaningful bytes in in. + * @return the number of bytes to discard, to the left of index position + * offset + length in in. In other words, if + * the return value of a successful invocation of this method is + * result, then the unpadded byte sequence will be + * offset + length - result bytes in in, + * starting from index position offset. + * @exception WrongPaddingException if the data is not terminated with the + * expected padding bytes. + */ + int unpad(byte[] in, int offset, int length) throws WrongPaddingException; + + /** + * Resets the scheme instance for re-initialisation and use with other + * characteristics. This method always succeeds. + */ + void reset(); + + /** + * A basic symmetric pad/unpad test. + * + * @return true if the implementation passes a basic symmetric + * self-test. Returns false otherwise. + */ + boolean selfTest(); +} diff --git a/libjava/classpath/gnu/javax/crypto/pad/ISO10126.java b/libjava/classpath/gnu/javax/crypto/pad/ISO10126.java new file mode 100644 index 000000000..8e8c59254 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/pad/ISO10126.java @@ -0,0 +1,109 @@ +/* ISO10126.java -- An implementation of the ISO 10126-2 padding scheme + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.pad; + +import gnu.java.security.Registry; +import gnu.java.security.util.PRNG; + +/** + * The implementation of the ISO 10126-2 padding algorithm. + *

+ * The last byte of the padding block is the number of padding bytes, all other + * padding bytes are random. + *

+ * References: + *

    + *
  1. XML Encryption Syntax and + * Processing Section "5.2 Block Encryption Algorithms"; "Padding".
  2. + *
+ */ +public final class ISO10126 + extends BasePad +{ + /** Used to generate random numbers for padding bytes. */ + private PRNG prng; + + ISO10126() + { + super(Registry.ISO10126_PAD); + prng = PRNG.getInstance(); + } + + public void setup() + { + // Nothing to do here + } + + public byte[] pad(byte[] in, int offset, int length) + { + int padLength = blockSize - (length % blockSize); + final byte[] pad = new byte[padLength]; + + // generate random numbers for the padding bytes except for the last byte + prng.nextBytes(pad, 0, padLength - 1); + // the last byte contains the number of padding bytes + pad[padLength - 1] = (byte) padLength; + + return pad; + } + + public int unpad(byte[] in, int offset, int length) + throws WrongPaddingException + { + // the last byte contains the number of padding bytes + int padLength = in[offset + length - 1] & 0xFF; + if (padLength > length) + throw new WrongPaddingException(); + + return padLength; + } + + /** + * The default self-test in the super-class would take too long to finish + * with this type of padder --due to the large amount of random data needed. + * We override the default test and replace it with a simple one for a 16-byte + * block-size (default AES block-size). The Mauve test TestOfISO10126 will + * exercise all block-sizes that the default self-test uses for the other + * padders. + */ + public boolean selfTest() + { + return test1BlockSize(16, new byte[1024]); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/pad/PKCS1_V1_5.java b/libjava/classpath/gnu/javax/crypto/pad/PKCS1_V1_5.java new file mode 100644 index 000000000..e303264ae --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/pad/PKCS1_V1_5.java @@ -0,0 +1,156 @@ +/* PKCS1_V1_5.java -- + Copyright (C) 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.crypto.pad; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.sig.rsa.EME_PKCS1_V1_5; +import gnu.java.security.util.PRNG; +import gnu.java.security.util.Util; + +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * A padding algorithm implementation of the EME-PKCS1-V1.5 encoding/decoding + * algorithm as described in section 7.2 of RFC-3447. This is effectively an + * Adapter over an instance of {@link EME_PKCS1_V1_5} initialised with + * the RSA public shared modulus length (in bytes). + *

+ * References: + *

    + *
  1. Public-Key Cryptography + * Standards (PKCS) #1:
    + * RSA Cryptography Specifications Version 2.1.
    + * Jakob Jonsson and Burt Kaliski.
  2. + *
+ * + * @see EME_PKCS1_V1_5 + */ +public class PKCS1_V1_5 + extends BasePad +{ + private static final Logger log = Logger.getLogger(PKCS1_V1_5.class.getName()); + private EME_PKCS1_V1_5 codec; + + /** + * Trivial package-private constructor for use by the Factory class. + * + * @see PadFactory + */ + PKCS1_V1_5() + { + super(Registry.EME_PKCS1_V1_5_PAD); + } + + public void setup() + { + codec = EME_PKCS1_V1_5.getInstance(blockSize); + } + + public byte[] pad(final byte[] in, final int offset, final int length) + { + final byte[] M = new byte[length]; + System.arraycopy(in, offset, M, 0, length); + final byte[] EM = codec.encode(M); + final byte[] result = new byte[blockSize - length]; + System.arraycopy(EM, 0, result, 0, result.length); + if (Configuration.DEBUG) + log.fine("padding: 0x" + Util.toString(result)); + return result; + } + + public int unpad(final byte[] in, final int offset, final int length) + throws WrongPaddingException + { + final byte[] EM = new byte[length]; + System.arraycopy(in, offset, EM, 0, length); + final int result = length - codec.decode(EM).length; + if (Configuration.DEBUG) + log.fine("padding length: " + String.valueOf(result)); + return result; + } + + public boolean selfTest() + { + final int[] mLen = new int[] { 16, 20, 32, 48, 64 }; + final byte[] M = new byte[mLen[mLen.length - 1]]; + PRNG.getInstance().nextBytes(M); + final byte[] EM = new byte[1024]; + byte[] p; + int bs, i, j; + for (bs = 256; bs < 1025; bs += 256) + { + init(bs); + for (i = 0; i < mLen.length; i++) + { + j = mLen[i]; + p = pad(M, 0, j); + if (j + p.length != blockSize) + { + if (Configuration.DEBUG) + log.log(Level.SEVERE, + "Length of padded text MUST be a multiple of " + + blockSize, new RuntimeException(name())); + return false; + } + System.arraycopy(p, 0, EM, 0, p.length); + System.arraycopy(M, 0, EM, p.length, j); + try + { + if (p.length != unpad(EM, 0, blockSize)) + { + if (Configuration.DEBUG) + log.log(Level.SEVERE, "Failed symmetric operation", + new RuntimeException(name())); + return false; + } + } + catch (WrongPaddingException x) + { + if (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "selfTest", x); + return false; + } + } + reset(); + } + return true; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/pad/PKCS7.java b/libjava/classpath/gnu/javax/crypto/pad/PKCS7.java new file mode 100644 index 000000000..9dd67fc81 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/pad/PKCS7.java @@ -0,0 +1,111 @@ +/* PKCS7.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + + This file is a part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at + your option) any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you 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.pad; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import java.util.logging.Logger; + +/** + * The implementation of the PKCS7 padding algorithm. + *

+ * This algorithm is described for 8-byte blocks in [RFC-1423] and extended to + * block sizes of up to 256 bytes in [PKCS-7]. + *

+ * References: + *

    + *
  1. RFC-1423: Privacy + * Enhancement for Internet Electronic Mail: Part III: Algorithms, Modes, and + * Identifiers.
  2. + *
  3. IETF.
  4. + *
  5. [PKCS-7] + * PKCS #7: Cryptographic Message Syntax Standard - An RSA Laboratories + * Technical Note.
  6. + *
  7. RSA Security.
  8. + *
+ */ +public final class PKCS7 + extends BasePad +{ + private static final Logger log = Logger.getLogger(PKCS7.class.getName()); + + /** + * Trivial package-private constructor for use by the Factory class. + * + * @see PadFactory + */ + PKCS7() + { + super(Registry.PKCS7_PAD); + } + + public void setup() + { + if (blockSize < 2 || blockSize > 256) + throw new IllegalArgumentException(); + } + + public byte[] pad(byte[] in, int offset, int length) + { + int padLength = blockSize; + if (length % blockSize != 0) + padLength = blockSize - length % blockSize; + byte[] result = new byte[padLength]; + for (int i = 0; i < padLength;) + result[i++] = (byte) padLength; + if (Configuration.DEBUG) + log.fine("padding: 0x" + Util.toString(result)); + return result; + } + + public int unpad(byte[] in, int offset, int length) + throws WrongPaddingException + { + int limit = offset + length; + int result = in[--limit] & 0xFF; + for (int i = 0; i < result - 1; i++) + if (result != (in[--limit] & 0xFF)) + throw new WrongPaddingException(); + if (Configuration.DEBUG) + log.fine("padding length: " + result); + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/pad/PadFactory.java b/libjava/classpath/gnu/javax/crypto/pad/PadFactory.java new file mode 100644 index 000000000..2df2029fa --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/pad/PadFactory.java @@ -0,0 +1,120 @@ +/* PadFactory.java -- + Copyright (C) 2001, 2002, 2003, 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.pad; + +import gnu.java.security.Registry; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * A Factory to instantiate padding schemes. + */ +public class PadFactory + implements Registry +{ + /** Collection of padding algorithm names --cached for speed. */ + private static Set names; + + /** Trivial constructor to enforce Singleton pattern. */ + private PadFactory() + { + super(); + } + + /** + * Returns an instance of a padding algorithm given its name. + * + * @param pad the case-insensitive name of the padding algorithm. + * @return an instance of the padding algorithm, operating with a given block + * size, or null if none found. + * @throws InternalError if the implementation does not pass its self-test. + */ + public static final IPad getInstance(String pad) + { + if (pad == null) + return null; + + pad = pad.trim().toLowerCase(); + if (pad.endsWith("padding")) + pad = pad.substring(0, pad.length() - "padding".length()); + IPad result = null; + if (pad.equals(PKCS7_PAD) || pad.equals(PKCS5_PAD)) + result = new PKCS7(); + else if (pad.equals(TBC_PAD)) + result = new TBC(); + else if (pad.equals(EME_PKCS1_V1_5_PAD)) + result = new PKCS1_V1_5(); + else if (pad.equals(SSL3_PAD)) + result = new SSL3(); + else if (pad.equals(TLS1_PAD)) + result = new TLS1(); + else if (pad.equals(ISO10126_PAD)) + result = new ISO10126(); + + if (result != null && ! result.selfTest()) + throw new InternalError(result.name()); + + return result; + } + + /** + * Returns a {@link Set} of names of padding algorithms supported by this + * Factory. + * + * @return a {@link Set} of padding algorithm names (Strings). + */ + public static final Set getNames() + { + if (names == null) + { + HashSet hs = new HashSet(); + hs.add(PKCS5_PAD); + hs.add(PKCS7_PAD); + hs.add(TBC_PAD); + hs.add(EME_PKCS1_V1_5_PAD); + hs.add(SSL3_PAD); + hs.add(TLS1_PAD); + hs.add(ISO10126_PAD); + names = Collections.unmodifiableSet(hs); + } + return names; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/pad/SSL3.java b/libjava/classpath/gnu/javax/crypto/pad/SSL3.java new file mode 100644 index 000000000..78964d619 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/pad/SSL3.java @@ -0,0 +1,90 @@ +/* SSL3.java -- SSLv3 padding scheme. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.pad; + +/** + * The padding scheme used by the Secure Sockets Layer, version 3. This padding + * scheme is used in the block-ciphered struct, e.g.: + *
+ *  block-ciphered struct {
+ *    opaque content[SSLCompressed.length];
+ *    opaque MAC[CipherSpec.hash_size];
+ *    uint8 padding[GenericBlockCipher.padding_length];
+ *    uint8 padding_length;
+ *  } GenericBlockCipher;
+ * 
+ *

+ * Where padding_length is cipher_block_size - + * ((SSLCompressed.length + CipherSpec.hash_size) % + * cipher_block_size) - 1. That is, the padding is enough bytes to make + * the plaintext a multiple of the block size minus one, plus one additional + * byte for the padding length. The padding can be any arbitrary data. + */ +public class SSL3 + extends BasePad +{ + public SSL3() + { + super("ssl3"); + } + + public void setup() + { + if (blockSize <= 0 || blockSize > 255) + throw new IllegalArgumentException("invalid block size: " + blockSize); + } + + public byte[] pad(final byte[] in, final int off, final int len) + { + int padlen = blockSize - (len % blockSize); + byte[] pad = new byte[padlen]; + for (int i = 0; i < padlen; i++) + pad[i] = (byte)(padlen - 1); + return pad; + } + + public int unpad(final byte[] in, final int off, final int len) + throws WrongPaddingException + { + int padlen = in[off + len - 1] & 0xFF; + if (padlen >= blockSize) + throw new WrongPaddingException(); + return padlen + 1; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/pad/TBC.java b/libjava/classpath/gnu/javax/crypto/pad/TBC.java new file mode 100644 index 000000000..5cd177058 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/pad/TBC.java @@ -0,0 +1,118 @@ +/* TBC.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.pad; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import java.util.logging.Logger; + +/** + * The implementation of the Trailing Bit Complement (TBC) padding algorithm. + *

+ * In this mode, "...the data string is padded at the trailing end with the + * complement of the trailing bit of the unpadded message: if the trailing bit + * is 1, then 0 bits are appended, and if the trailing + * bit is 0, then 1 bits are appended. As few bits are + * added as are necessary to meet the formatting size requirement." + *

+ * References: + *

    + *
  1. + * Recommendation for Block Cipher Modes of Operation Methods and + * Techniques, Morris Dworkin.
  2. + *
+ */ +public final class TBC + extends BasePad +{ + private static final Logger log = Logger.getLogger(TBC.class.getName()); + + /** + * Trivial package-private constructor for use by the Factory class. + * + * @see PadFactory + */ + TBC() + { + super(Registry.TBC_PAD); + } + + public void setup() + { + if (blockSize < 1 || blockSize > 256) + throw new IllegalArgumentException(); + } + + public byte[] pad(byte[] in, int offset, int length) + { + int padLength = blockSize; + if (length % blockSize != 0) + padLength = blockSize - length % blockSize; + byte[] result = new byte[padLength]; + int lastBit = in[offset + length - 1] & 0x01; + if (lastBit == 0) + for (int i = 0; i < padLength;) + result[i++] = 0x01; + // else it's already set to zeroes by virtue of initialisation + if (Configuration.DEBUG) + log.fine("padding: 0x" + Util.toString(result)); + return result; + } + + public int unpad(byte[] in, int offset, int length) + throws WrongPaddingException + { + int limit = offset + length - 1; + int lastBit = in[limit] & 0xFF; + int result = 0; + while (lastBit == (in[limit] & 0xFF)) + { + result++; + limit--; + } + if (result > length) + throw new WrongPaddingException(); + if (Configuration.DEBUG) + log.fine("padding length: " + result); + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/pad/TLS1.java b/libjava/classpath/gnu/javax/crypto/pad/TLS1.java new file mode 100644 index 000000000..1d690dd59 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/pad/TLS1.java @@ -0,0 +1,91 @@ +/* TLS1.java -- TLSv1 padding scheme. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.pad; + +/** + * The padding scheme used by the Transport Layer Security protocol, version 1. + * This padding scheme is used in the block-ciphered struct, e.g.: + *
+ *  block-ciphered struct {
+ *    opaque content[TLSCompressed.length];
+ *    opaque MAC[CipherSpec.hash_size];
+ *    uint8 padding[GenericBlockCipher.padding_length];
+ *    uint8 padding_length;
+ *  } GenericBlockCipher;
+ * 
+ *

+ * Where padding_length is any multiple of cipher_block_size - + * ((SSLCompressed.length + CipherSpec.hash_size) % + * cipher_block_size) - 1 that is less than 255. Every byte of the + * padding must be equal to padding_length. That is, the end of the + * plaintext is n + 1 copies of the unsigned byte n. + */ +public class TLS1 + extends BasePad +{ + public TLS1() + { + super("tls1"); + } + + public void setup() + { + if (blockSize <= 0 || blockSize > 255) + throw new IllegalArgumentException("invalid block size: " + blockSize); + } + + public byte[] pad(final byte[] in, final int off, final int len) + { + int padlen = blockSize - (len % blockSize); + byte[] pad = new byte[padlen]; + for (int i = 0; i < padlen; i++) + pad[i] = (byte)(padlen - 1); + return pad; + } + + public int unpad(final byte[] in, final int off, final int len) + throws WrongPaddingException + { + int padlen = in[off + len - 1] & 0xFF; + for (int i = off + (len - padlen - 1); i < off + len - 1; i++) + if ((in[i] & 0xFF) != padlen) + throw new WrongPaddingException(); + return padlen + 1; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/pad/WrongPaddingException.java b/libjava/classpath/gnu/javax/crypto/pad/WrongPaddingException.java new file mode 100644 index 000000000..d15723faf --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/pad/WrongPaddingException.java @@ -0,0 +1,48 @@ +/* WrongPaddingException.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.pad; + +/** + * A checked exception that indicates that a padding algorithm did not find the + * expected padding bytes when unpadding some data. + */ +public class WrongPaddingException + extends Exception +{ +} diff --git a/libjava/classpath/gnu/javax/crypto/prng/ARCFour.java b/libjava/classpath/gnu/javax/crypto/prng/ARCFour.java new file mode 100644 index 000000000..60464d5ba --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/prng/ARCFour.java @@ -0,0 +1,137 @@ +/* ARCFour.java -- + Copyright (C) 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.crypto.prng; + +import gnu.java.security.Registry; +import gnu.java.security.prng.BasePRNG; +import gnu.java.security.prng.LimitReachedException; + +import java.util.Map; + +/** + * RC4 is a stream cipher developed by Ron Rivest. Until 1994 RC4 was a trade + * secret of RSA Data Security, Inc., when it was released anonymously to a + * mailing list. This version is a descendent of that code, and since there is + * no proof that the leaked version was in fact RC4 and because "RC4" is a + * trademark, it is called "ARCFOUR", short for "Allegedly RC4". + *

+ * This class only implements the keystream of ARCFOUR. To use this as a + * stream cipher, one would say: + *

+ * out = in ˆ arcfour.nextByte();
+ * 
+ *

+ * This operation works for encryption and decryption. + *

+ * References: + *

    + *
  1. Schneier, Bruce: Applied Cryptography: Protocols, Algorithms, and + * Source Code in C, Second Edition. (1996 John Wiley and Sons), pp. + * 397--398. ISBN 0-471-11709-9
  2. + *
  3. K. Kaukonen and R. Thayer, "A Stream Cipher Encryption Algorithm + * 'Arcfour'", Internet Draft (expired), draft-kaukonen-cipher-arcfour-03.txt
  4. + *
+ */ +public class ARCFour + extends BasePRNG + implements Cloneable +{ + /** The attributes property name for the key bytes. */ + public static final String ARCFOUR_KEY_MATERIAL = "gnu.crypto.prng.arcfour.key-material"; + /** The size of the internal S-box. */ + public static final int ARCFOUR_SBOX_SIZE = 256; + /** The S-box. */ + private byte[] s; + private byte m, n; + + /** Default 0-arguments constructor. */ + public ARCFour() + { + super(Registry.ARCFOUR_PRNG); + } + + public void setup(Map attributes) + { + byte[] kb = (byte[]) attributes.get(ARCFOUR_KEY_MATERIAL); + if (kb == null) + throw new IllegalArgumentException("ARCFOUR needs a key"); + s = new byte[ARCFOUR_SBOX_SIZE]; + m = n = 0; + byte[] k = new byte[ARCFOUR_SBOX_SIZE]; + for (int i = 0; i < ARCFOUR_SBOX_SIZE; i++) + s[i] = (byte) i; + if (kb.length > 0) + for (int i = 0, j = 0; i < ARCFOUR_SBOX_SIZE; i++) + { + k[i] = kb[j++]; + if (j >= kb.length) + j = 0; + } + for (int i = 0, j = 0; i < ARCFOUR_SBOX_SIZE; i++) + { + j = j + s[i] + k[i]; + byte temp = s[i]; + s[i] = s[j & 0xff]; + s[j & 0xff] = temp; + } + buffer = new byte[ARCFOUR_SBOX_SIZE]; + try + { + fillBlock(); + } + catch (LimitReachedException wontHappen) + { + } + } + + public void fillBlock() throws LimitReachedException + { + for (int i = 0; i < buffer.length; i++) + { + m++; + n = (byte)(n + s[m & 0xff]); + byte temp = s[m & 0xff]; + s[m & 0xff] = s[n & 0xff]; + s[n & 0xff] = temp; + temp = (byte)(s[m & 0xff] + s[n & 0xff]); + buffer[i] = s[temp & 0xff]; + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/prng/CSPRNG.java b/libjava/classpath/gnu/javax/crypto/prng/CSPRNG.java new file mode 100644 index 000000000..ecea2f469 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/prng/CSPRNG.java @@ -0,0 +1,985 @@ +/* CSPRNG.java -- continuously-seeded pseudo-random number generator. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.prng; + +import gnu.java.security.Configuration; +import gnu.java.security.Properties; +import gnu.java.security.Registry; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.prng.BasePRNG; +import gnu.java.security.prng.EntropySource; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.SimpleList; +import gnu.java.security.util.Util; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; + +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.PrintStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.AccessController; +import java.security.InvalidKeyException; +import java.security.PrivilegedAction; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * An entropy pool-based pseudo-random number generator based on the PRNG in + * Peter Gutmann's cryptlib (http://www.cs.auckland.ac.nz/~pgut001/cryptlib/). + *

+ * The basic properties of this generator are: + *

    + *
  1. The internal state cannot be determined by knowledge of the input.
  2. + *
  3. It is resistant to bias introduced by specific inputs.
  4. + *
  5. The output does not reveal the state of the generator.
  6. + *
+ */ +public class CSPRNG + extends BasePRNG +{ + private static final Logger log = Logger.getLogger(CSPRNG.class.getName()); + /** + * Property name for the list of files to read for random values. The mapped + * value is a list with the following values: + *
    + *
  1. A {@link Double}, indicating the suggested quality of this + * source. This value must be between 0 and 100.
  2. + *
  3. An {@link Integer}, indicating the number of bytes to skip in the + * file before reading bytes. This can be any nonnegative value.
  4. + *
  5. An {@link Integer}, indicating the number of bytes to read.
  6. + *
  7. A {@link String}, indicating the path to the file.
  8. + *
+ * + * @see gnu.java.security.util.SimpleList + */ + public static final String FILE_SOURCES = "gnu.crypto.prng.pool.files"; + /** + * Property name for the list of URLs to poll for random values. The mapped + * value is a list formatted similarly as in {@link #FILE_SOURCES}, but the + * fourth member is a {@link URL}. + */ + public static final String URL_SOURCES = "gnu.crypto.prng.pool.urls"; + /** + * Property name for the list of programs to execute, and use the output as + * new random bytes. The mapped property is formatted similarly an in + * {@link #FILE_SOURCES} and {@link #URL_SOURCES}, except the fourth member + * is a {@link String} of the program to execute. + */ + public static final String PROGRAM_SOURCES = "gnu.crypto.prng.pool.programs"; + /** + * Property name for a list of other sources of entropy. The mapped value must + * be a list of {@link EntropySource} objects. + */ + public static final String OTHER_SOURCES = "gnu.crypto.prng.pool.other"; + /** + * Property name for whether or not to wait for the slow poll to complete, + * passed as a {@link Boolean}. The default value is true. + */ + public static final String BLOCKING = "gnu.crypto.prng.pool.blocking"; + private static final String FILES = "gnu.crypto.csprng.file."; + private static final String URLS = "gnu.crypto.csprng.url."; + private static final String PROGS = "gnu.crypto.csprng.program."; + private static final String OTHER = "gnu.crypto.csprng.other."; + private static final String BLOCK = "gnu.crypto.csprng.blocking"; + private static final int POOL_SIZE = 256; + private static final int ALLOC_SIZE = 260; + private static final int OUTPUT_SIZE = POOL_SIZE / 2; + private static final int X917_POOL_SIZE = 16; + private static final String HASH_FUNCTION = Registry.SHA160_HASH; + private static final String CIPHER = Registry.AES_CIPHER; + private static final int MIX_COUNT = 10; + private static final int X917_LIFETIME = 8192; + // FIXME this should be configurable. + private static final int SPINNER_COUNT = 8; + /** + * The spinner group singleton. We use this to add a small amount of + * randomness (in addition to the current time and the amount of free memory) + * based on the randomness (if any) present due to system load and thread + * scheduling. + */ + private static final Spinner[] SPINNERS = new Spinner[SPINNER_COUNT]; + private static final Thread[] SPINNER_THREADS = new Thread[SPINNER_COUNT]; + static + { + for (int i = 0; i < SPINNER_COUNT; i++) + { + SPINNER_THREADS[i] = new Thread(SPINNERS[i] = new Spinner(), + "spinner-" + i); + SPINNER_THREADS[i].setDaemon(true); + SPINNER_THREADS[i].setPriority(Thread.MIN_PRIORITY); + SPINNER_THREADS[i].start(); + } + } + /** The message digest (SHA-1) used in the mixing function. */ + private final IMessageDigest hash; + /** The cipher (AES) used in the output masking function. */ + private final IBlockCipher cipher; + /** The number of times the pool has been mixed. */ + private int mixCount; + /** The entropy pool. */ + private final byte[] pool; + /** The quality of the random pool (percentage). */ + private double quality; + /** The index of the next byte in the entropy pool. */ + private int index; + /** The pool for the X9.17-like generator. */ + private byte[] x917pool; + /** The number of iterations of the X9.17-like generators. */ + private int x917count; + /** Whether or not the X9.17-like generator is initialized. */ + private boolean x917init; + /** The list of file soures. */ + private final List files; + /** The list of URL sources. */ + private final List urls; + /** The list of program sources. */ + private final List progs; + /** The list of other sources. */ + private final List other; + /** Whether or not to wait for the slow poll to complete. */ + private boolean blocking; + /** The thread that polls for random data. */ + private Poller poller; + private Thread pollerThread; + + public CSPRNG() + { + super("CSPRNG"); + pool = new byte[ALLOC_SIZE]; + x917pool = new byte[X917_POOL_SIZE]; + x917count = 0; + x917init = false; + quality = 0.0; + hash = HashFactory.getInstance(HASH_FUNCTION); + cipher = CipherFactory.getInstance(CIPHER); + buffer = new byte[OUTPUT_SIZE]; + ndx = 0; + initialised = false; + files = new LinkedList(); + urls = new LinkedList(); + progs = new LinkedList(); + other = new LinkedList(); + } + + /** + * Create and initialize a CSPRNG instance with the "system" parameters; the + * files, URLs, programs, and {@link EntropySource} sources used by the + * instance are derived from properties set in the system {@link Properties}. + *

+ * All properties are of the from name.N, where name + * is the name of the source, and N is an integer (staring at 1) that + * indicates the preference number for that source. + *

+ * The following vales for name are used here: + *

+ *
gnu.crypto.csprng.file
+ *
+ *

+ * These properties are file sources, passed as the {@link #FILE_SOURCES} + * parameter of the instance. The property value is a 4-tuple formatted as: + *

+ *
quality ; offset ; count ; path
+ *

+ * The parameters are mapped to the parameters defined for {@link + * #FILE_SOURCES}. Leading or trailing spaces on any item are trimmed off. + *

+ *
+ *
gnu.crypto.csprng.url
+ *
+ *

+ * These properties are URL sources, passed as the {@link #URL_SOURCES} + * parameter of the instance. The property is formatted the same way as file + * sources, but the path argument must be a valid URL. + *

+ *
+ *
gnu.crypto.csprng.program
+ *
+ *

+ * These properties are program sources, passed as the {@link + * #PROGRAM_SOURCES} parameter of the instance. This property is formatted the + * same way as file and URL sources, but the last argument is a program and + * its arguments. + *

+ *
+ *
gnu.crypto.cspring.other
+ *
+ *

+ * These properties are other sources, passed as the {@link #OTHER_SOURCES} + * parameter of the instance. The property value must be the full name of a + * class that implements the {@link EntropySource} interface and has a public + * no-argument constructor. + *

+ *
+ *
+ *

+ * Finally, a boolean property "gnu.crypto.csprng.blocking" can be set to the + * desired value of {@link #BLOCKING}. + *

+ * An example of valid properties would be: + *

+   *  gnu.crypto.csprng.blocking=true
+   *
+   *  gnu.crypto.csprng.file.1=75.0;0;256;/dev/random
+   *  gnu.crypto.csprng.file.2=10.0;0;100;/home/user/file
+   *
+   *  gnu.crypto.csprng.url.1=5.0;0;256;http://www.random.org/cgi-bin/randbyte?nbytes=256
+   *  gnu.crypto.csprng.url.2=0;256;256;http://slashdot.org/
+   *
+   *  gnu.crypto.csprng.program.1=0.5;0;10;last -n 50
+   *  gnu.crypto.csprng.program.2=0.5;0;10;tcpdump -c 5
+   *
+   *  gnu.crypto.csprng.other.1=foo.bar.MyEntropySource
+   *  gnu.crypto.csprng.other.2=com.company.OtherEntropySource
+   * 
+ */ + public static IRandom getSystemInstance() throws ClassNotFoundException, + MalformedURLException, NumberFormatException + { + CSPRNG instance = new CSPRNG(); + HashMap attrib = new HashMap(); + attrib.put(BLOCKING, Boolean.valueOf(getProperty(BLOCK))); + String s = null; + // Get each file source "gnu.crypto.csprng.file.N". + List l = new LinkedList(); + for (int i = 0; (s = getProperty(FILES + i)) != null; i++) + try + { + l.add(parseString(s.trim())); + } + catch (NumberFormatException nfe) + { + } + attrib.put(FILE_SOURCES, l); + l = new LinkedList(); + for (int i = 0; (s = getProperty(URLS + i)) != null; i++) + try + { + l.add(parseURL(s.trim())); + } + catch (NumberFormatException nfe) + { + } + catch (MalformedURLException mue) + { + } + attrib.put(URL_SOURCES, l); + l = new LinkedList(); + for (int i = 0; (s = getProperty(PROGS + i)) != null; i++) + try + { + l.add(parseString(s.trim())); + } + catch (NumberFormatException nfe) + { + } + attrib.put(PROGRAM_SOURCES, l); + l = new LinkedList(); + for (int i = 0; (s = getProperty(OTHER + i)) != null; i++) + try + { + Class c = Class.forName(s.trim()); + l.add(c.newInstance()); + } + catch (ClassNotFoundException cnfe) + { + } + catch (InstantiationException ie) + { + } + catch (IllegalAccessException iae) + { + } + attrib.put(OTHER_SOURCES, l); + instance.init(attrib); + return instance; + } + + private static String getProperty(final String name) + { + return (String) AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + return Properties.getProperty(name); + } + }); + } + + private static List parseString(String s) throws NumberFormatException + { + StringTokenizer tok = new StringTokenizer(s, ";"); + if (tok.countTokens() != 4) + throw new IllegalArgumentException("malformed property"); + Double quality = new Double(tok.nextToken()); + Integer offset = new Integer(tok.nextToken()); + Integer length = new Integer(tok.nextToken()); + String str = tok.nextToken(); + return new SimpleList(quality, offset, length, str); + } + + private static List parseURL(String s) throws MalformedURLException, + NumberFormatException + { + StringTokenizer tok = new StringTokenizer(s, ";"); + if (tok.countTokens() != 4) + throw new IllegalArgumentException("malformed property"); + Double quality = new Double(tok.nextToken()); + Integer offset = new Integer(tok.nextToken()); + Integer length = new Integer(tok.nextToken()); + URL url = new URL(tok.nextToken()); + return new SimpleList(quality, offset, length, url); + } + + public Object clone() + { + return new CSPRNG(); + } + + public void setup(Map attrib) + { + List list = null; + if (Configuration.DEBUG) + log.fine("attrib=" + String.valueOf(attrib)); + try + { + list = (List) attrib.get(FILE_SOURCES); + if (Configuration.DEBUG) + log.fine("list=" + String.valueOf(list)); + if (list != null) + { + files.clear(); + for (Iterator it = list.iterator(); it.hasNext();) + { + List l = (List) it.next(); + if (Configuration.DEBUG) + log.fine("l=" + l); + if (l.size() != 4) + { + if (Configuration.DEBUG) + log.fine("file list too small: " + l.size()); + throw new IllegalArgumentException("invalid file list"); + } + Double quality = (Double) l.get(0); + Integer offset = (Integer) l.get(1); + Integer length = (Integer) l.get(2); + String source = (String) l.get(3); + files.add(new SimpleList(quality, offset, length, source)); + } + } + } + catch (ClassCastException cce) + { + if (Configuration.DEBUG) + log.log(Level.FINE, "bad file list", cce); + throw new IllegalArgumentException("invalid file list"); + } + try + { + list = (List) attrib.get(URL_SOURCES); + if (Configuration.DEBUG) + log.fine("list=" + String.valueOf(list)); + if (list != null) + { + urls.clear(); + for (Iterator it = list.iterator(); it.hasNext();) + { + List l = (List) it.next(); + if (Configuration.DEBUG) + log.fine("l=" + l); + if (l.size() != 4) + { + if (Configuration.DEBUG) + log.fine("URL list too small: " + l.size()); + throw new IllegalArgumentException("invalid URL list"); + } + Double quality = (Double) l.get(0); + Integer offset = (Integer) l.get(1); + Integer length = (Integer) l.get(2); + URL source = (URL) l.get(3); + urls.add(new SimpleList(quality, offset, length, source)); + } + } + } + catch (ClassCastException cce) + { + if (Configuration.DEBUG) + log.log(Level.FINE, "bad URL list", cce); + throw new IllegalArgumentException("invalid URL list"); + } + try + { + list = (List) attrib.get(PROGRAM_SOURCES); + if (Configuration.DEBUG) + log.fine("list=" + String.valueOf(list)); + if (list != null) + { + progs.clear(); + for (Iterator it = list.iterator(); it.hasNext();) + { + List l = (List) it.next(); + if (Configuration.DEBUG) + log.fine("l=" + l); + if (l.size() != 4) + { + if (Configuration.DEBUG) + log.fine("program list too small: " + l.size()); + throw new IllegalArgumentException("invalid program list"); + } + Double quality = (Double) l.get(0); + Integer offset = (Integer) l.get(1); + Integer length = (Integer) l.get(2); + String source = (String) l.get(3); + progs.add(new SimpleList(quality, offset, length, source)); + } + } + } + catch (ClassCastException cce) + { + if (Configuration.DEBUG) + log.log(Level.FINE, "bad program list", cce); + throw new IllegalArgumentException("invalid program list"); + } + try + { + list = (List) attrib.get(OTHER_SOURCES); + if (Configuration.DEBUG) + log.fine("list=" + String.valueOf(list)); + if (list != null) + { + other.clear(); + for (Iterator it = list.iterator(); it.hasNext();) + { + EntropySource src = (EntropySource) it.next(); + if (Configuration.DEBUG) + log.fine("src=" + src); + if (src == null) + throw new NullPointerException("null source in source list"); + other.add(src); + } + } + } + catch (ClassCastException cce) + { + throw new IllegalArgumentException("invalid source list"); + } + + try + { + Boolean block = (Boolean) attrib.get(BLOCKING); + if (block != null) + blocking = block.booleanValue(); + else + blocking = true; + } + catch (ClassCastException cce) + { + throw new IllegalArgumentException("invalid blocking parameter"); + } + poller = new Poller(files, urls, progs, other, this); + try + { + fillBlock(); + } + catch (LimitReachedException lre) + { + throw new RuntimeException("bootstrapping CSPRNG failed"); + } + } + + public void fillBlock() throws LimitReachedException + { + if (Configuration.DEBUG) + log.fine("fillBlock"); + if (getQuality() < 100.0) + { + if (Configuration.DEBUG) + log.fine("doing slow poll"); + slowPoll(); + } + do + { + fastPoll(); + mixRandomPool(); + } + while (mixCount < MIX_COUNT); + if (! x917init || x917count >= X917_LIFETIME) + { + mixRandomPool(pool); + Map attr = new HashMap(); + byte[] key = new byte[32]; + System.arraycopy(pool, 0, key, 0, 32); + cipher.reset(); + attr.put(IBlockCipher.KEY_MATERIAL, key); + try + { + cipher.init(attr); + } + catch (InvalidKeyException ike) + { + throw new Error(ike.toString()); + } + mixRandomPool(pool); + generateX917(pool); + mixRandomPool(pool); + generateX917(pool); + if (x917init) + quality = 0.0; + x917init = true; + x917count = 0; + } + byte[] export = new byte[ALLOC_SIZE]; + for (int i = 0; i < ALLOC_SIZE; i++) + export[i] = (byte)(pool[i] ^ 0xFF); + mixRandomPool(); + mixRandomPool(export); + generateX917(export); + for (int i = 0; i < OUTPUT_SIZE; i++) + buffer[i] = (byte)(export[i] ^ export[i + OUTPUT_SIZE]); + Arrays.fill(export, (byte) 0); + } + + /** + * Add an array of bytes into the randomness pool. Note that this method will + * not increment the pool's quality counter (this can only be done via + * a source provided to the setup method). + * + * @param buf The byte array. + * @param off The offset from whence to start reading bytes. + * @param len The number of bytes to add. + * @throws ArrayIndexOutOfBoundsException If off or len are + * out of the range of buf. + */ + public synchronized void addRandomBytes(byte[] buf, int off, int len) + { + if (off < 0 || len < 0 || off + len > buf.length) + throw new ArrayIndexOutOfBoundsException(); + if (Configuration.DEBUG) + { + log.fine("adding random bytes:"); + log.fine(Util.toString(buf, off, len)); + } + final int count = off + len; + for (int i = off; i < count; i++) + { + pool[index++] ^= buf[i]; + if (index == pool.length) + { + mixRandomPool(); + index = 0; + } + } + } + + /** + * Add a single random byte to the randomness pool. Note that this method will + * not increment the pool's quality counter (this can only be done via + * a source provided to the setup method). + * + * @param b The byte to add. + */ + public synchronized void addRandomByte(byte b) + { + if (Configuration.DEBUG) + log.fine("adding byte " + Integer.toHexString(b)); + pool[index++] ^= b; + if (index >= pool.length) + { + mixRandomPool(); + index = 0; + } + } + + synchronized void addQuality(double quality) + { + if (Configuration.DEBUG) + log.fine("adding quality " + quality); + if (this.quality < 100) + this.quality += quality; + if (Configuration.DEBUG) + log.fine("quality now " + this.quality); + } + + synchronized double getQuality() + { + return quality; + } + + /** + * The mix operation. This method will, for every 20-byte block in the random + * pool, hash that block, the previous 20 bytes, and the next 44 bytes with + * SHA-1, writing the result back into that block. + */ + private void mixRandomPool(byte[] buf) + { + int hashSize = hash.hashSize(); + for (int i = 0; i < buf.length; i += hashSize) + { + // First update the bytes [p-19..p-1]. + if (i == 0) + hash.update(buf, buf.length - hashSize, hashSize); + else + hash.update(buf, i - hashSize, hashSize); + // Now the next 64 bytes. + if (i + 64 < buf.length) + hash.update(buf, i, 64); + else + { + hash.update(buf, i, buf.length - i); + hash.update(buf, 0, 64 - (buf.length - i)); + } + byte[] digest = hash.digest(); + System.arraycopy(digest, 0, buf, i, hashSize); + } + } + + private void mixRandomPool() + { + mixRandomPool(pool); + mixCount++; + } + + private void generateX917(byte[] buf) + { + int off = 0; + for (int i = 0; i < buf.length; i += X917_POOL_SIZE) + { + int copy = Math.min(buf.length - i, X917_POOL_SIZE); + for (int j = 0; j < copy; j++) + x917pool[j] ^= pool[off + j]; + cipher.encryptBlock(x917pool, 0, x917pool, 0); + System.arraycopy(x917pool, 0, buf, off, copy); + cipher.encryptBlock(x917pool, 0, x917pool, 0); + off += copy; + x917count++; + } + } + + /** + * Add random data always immediately available into the random pool, such as + * the values of the eight asynchronous counters, the current time, the + * current memory usage, the calling thread name, and the current stack trace. + *

+ * This method does not alter the quality counter, and is provided more to + * maintain randomness, not to seriously improve the current random state. + */ + private void fastPoll() + { + byte b = 0; + for (int i = 0; i < SPINNER_COUNT; i++) + b ^= SPINNERS[i].counter; + addRandomByte(b); + addRandomByte((byte) System.currentTimeMillis()); + addRandomByte((byte) Runtime.getRuntime().freeMemory()); + String s = Thread.currentThread().getName(); + if (s != null) + { + byte[] buf = s.getBytes(); + addRandomBytes(buf, 0, buf.length); + } + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + PrintStream pout = new PrintStream(bout); + Throwable t = new Throwable(); + t.printStackTrace(pout); + pout.flush(); + byte[] buf = bout.toByteArray(); + addRandomBytes(buf, 0, buf.length); + } + + private void slowPoll() throws LimitReachedException + { + if (Configuration.DEBUG) + log.fine("poller is alive? " + + (pollerThread == null ? false : pollerThread.isAlive())); + if (pollerThread == null || ! pollerThread.isAlive()) + { + boolean interrupted = false; + pollerThread = new Thread(poller); + pollerThread.setDaemon(true); + pollerThread.setPriority(Thread.NORM_PRIORITY - 1); + pollerThread.start(); + if (blocking) + try + { + pollerThread.join(); + } + catch (InterruptedException ie) + { + interrupted = true; + } + // If the full slow poll has completed after we waited for it, + // and there in insufficient randomness, throw an exception. + if (! interrupted && blocking && quality < 100.0) + { + if (Configuration.DEBUG) + log.fine("insufficient quality: " + quality); + throw new LimitReachedException("insufficient randomness was polled"); + } + } + } + + protected void finalize() throws Throwable + { + if (poller != null && pollerThread != null && pollerThread.isAlive()) + { + pollerThread.interrupt(); + poller.stopUpdating(); + pollerThread.interrupt(); + } + Arrays.fill(pool, (byte) 0); + Arrays.fill(x917pool, (byte) 0); + Arrays.fill(buffer, (byte) 0); + } + + /** + * A simple thread that constantly updates a byte counter. This class is used + * in a group of lowest-priority threads and the values of their counters + * (updated in competition with all other threads) is used as a source of + * entropy bits. + */ + private static class Spinner + implements Runnable + { + protected byte counter; + + private Spinner() + { + } + + public void run() + { + while (true) + { + counter++; + try + { + Thread.sleep(100); + } + catch (InterruptedException ie) + { + } + } + } + } + + private final class Poller + implements Runnable + { + private final List files; + private final List urls; + private final List progs; + private final List other; + private final CSPRNG pool; + private boolean running; + + Poller(List files, List urls, List progs, List other, CSPRNG pool) + { + super(); + this.files = Collections.unmodifiableList(files); + this.urls = Collections.unmodifiableList(urls); + this.progs = Collections.unmodifiableList(progs); + this.other = Collections.unmodifiableList(other); + this.pool = pool; + } + + public void run() + { + running = true; + if (Configuration.DEBUG) + { + log.fine("files: " + files); + log.fine("URLs: " + urls); + log.fine("progs: " + progs); + } + Iterator files_it = files.iterator(); + Iterator urls_it = urls.iterator(); + Iterator prog_it = progs.iterator(); + Iterator other_it = other.iterator(); + + while (files_it.hasNext() || urls_it.hasNext() || prog_it.hasNext() + || other_it.hasNext()) + { + // There is enough random data. Go away. + if (pool.getQuality() >= 100.0 || ! running) + return; + if (files_it.hasNext()) + try + { + List l = (List) files_it.next(); + if (Configuration.DEBUG) + log.fine(l.toString()); + double qual = ((Double) l.get(0)).doubleValue(); + int offset = ((Integer) l.get(1)).intValue(); + int count = ((Integer) l.get(2)).intValue(); + String src = (String) l.get(3); + InputStream in = new FileInputStream(src); + byte[] buf = new byte[count]; + if (offset > 0) + in.skip(offset); + int len = in.read(buf); + if (len >= 0) + { + pool.addRandomBytes(buf, 0, len); + pool.addQuality(qual * ((double) len / (double) count)); + } + if (Configuration.DEBUG) + log.fine("got " + len + " bytes from " + src); + } + catch (Exception x) + { + if (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "run", x); + } + if (pool.getQuality() >= 100.0 || ! running) + return; + if (urls_it.hasNext()) + try + { + List l = (List) urls_it.next(); + if (Configuration.DEBUG) + log.fine(l.toString()); + double qual = ((Double) l.get(0)).doubleValue(); + int offset = ((Integer) l.get(1)).intValue(); + int count = ((Integer) l.get(2)).intValue(); + URL src = (URL) l.get(3); + InputStream in = src.openStream(); + byte[] buf = new byte[count]; + if (offset > 0) + in.skip(offset); + int len = in.read(buf); + if (len >= 0) + { + pool.addRandomBytes(buf, 0, len); + pool.addQuality(qual * ((double) len / (double) count)); + } + if (Configuration.DEBUG) + log.fine("got " + len + " bytes from " + src); + } + catch (Exception x) + { + if (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "run", x); + } + if (pool.getQuality() >= 100.0 || ! running) + return; + Process proc = null; + if (prog_it.hasNext()) + try + { + List l = (List) prog_it.next(); + if (Configuration.DEBUG) + log.finer(l.toString()); + double qual = ((Double) l.get(0)).doubleValue(); + int offset = ((Integer) l.get(1)).intValue(); + int count = ((Integer) l.get(2)).intValue(); + String src = (String) l.get(3); + proc = null; + proc = Runtime.getRuntime().exec(src); + InputStream in = proc.getInputStream(); + byte[] buf = new byte[count]; + if (offset > 0) + in.skip(offset); + int len = in.read(buf); + if (len >= 0) + { + pool.addRandomBytes(buf, 0, len); + pool.addQuality(qual * ((double) len / (double) count)); + } + proc.destroy(); + proc.waitFor(); + if (Configuration.DEBUG) + log.fine("got " + len + " bytes from " + src); + } + catch (Exception x) + { + if (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "run", x); + try + { + if (proc != null) + { + proc.destroy(); + proc.waitFor(); + } + } + catch (Exception ignored) + { + } + } + if (pool.getQuality() >= 100.0 || ! running) + return; + if (other_it.hasNext()) + try + { + EntropySource src = (EntropySource) other_it.next(); + byte[] buf = src.nextBytes(); + if (pool == null) + return; + pool.addRandomBytes(buf, 0, buf.length); + pool.addQuality(src.quality()); + if (Configuration.DEBUG) + log.fine("got " + buf.length + " bytes from " + src); + } + catch (Exception x) + { + if (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "run", x); + } + } + } + + public void stopUpdating() + { + running = false; + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/prng/Fortuna.java b/libjava/classpath/gnu/javax/crypto/prng/Fortuna.java new file mode 100644 index 000000000..8aec9ab7d --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/prng/Fortuna.java @@ -0,0 +1,349 @@ +/* Fortuna.java -- The Fortuna PRNG. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.prng; + +import gnu.java.security.Registry; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.prng.BasePRNG; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.prng.RandomEvent; +import gnu.java.security.prng.RandomEventListener; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.security.InvalidKeyException; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; + +/** + * The Fortuna continuously-seeded pseudo-random number generator. This + * generator is composed of two major pieces: the entropy accumulator and the + * generator function. The former takes in random bits and incorporates them + * into the generator's state. The latter takes this base entropy and generates + * pseudo-random bits from it. + *

+ * There are some things users of this class must be aware of: + *

+ *
Adding Random Data
+ *
This class does not do any polling of random sources, but rather + * provides an interface for adding random events. Applications that use this + * code must provide this mechanism. We use this design because an + * application writer who knows the system he is targeting is in a better + * position to judge what random data is available.
+ *
Storing the Seed
+ *
This class implements {@link Serializable} in such a way that it writes + * a 64 byte seed to the stream, and reads it back again when being + * deserialized. This is the extent of seed file management, however, and those + * using this class are encouraged to think deeply about when, how often, and + * where to store the seed.
+ *
+ *

+ * References: + *

+ */ +public class Fortuna + extends BasePRNG + implements Serializable, RandomEventListener +{ + private static final long serialVersionUID = 0xFACADE; + private static final int SEED_FILE_SIZE = 64; + private static final int NUM_POOLS = 32; + private static final int MIN_POOL_SIZE = 64; + private final Generator generator; + private final IMessageDigest[] pools; + private long lastReseed; + private int pool; + private int pool0Count; + private int reseedCount; + public static final String SEED = "gnu.crypto.prng.fortuna.seed"; + + public Fortuna() + { + super(Registry.FORTUNA_PRNG); + generator = new Generator(CipherFactory.getInstance(Registry.RIJNDAEL_CIPHER), + HashFactory.getInstance(Registry.SHA256_HASH)); + pools = new IMessageDigest[NUM_POOLS]; + for (int i = 0; i < NUM_POOLS; i++) + pools[i] = HashFactory.getInstance(Registry.SHA256_HASH); + lastReseed = 0; + pool = 0; + pool0Count = 0; + buffer = new byte[256]; + } + + public void setup(Map attributes) + { + lastReseed = 0; + reseedCount = 0; + pool = 0; + pool0Count = 0; + generator.init(attributes); + try + { + fillBlock(); + } + catch (LimitReachedException shouldNotHappen) + { + throw new RuntimeException(shouldNotHappen); + } + } + + public void fillBlock() throws LimitReachedException + { + if (pool0Count >= MIN_POOL_SIZE + && System.currentTimeMillis() - lastReseed > 100) + { + reseedCount++; + byte[] seed = new byte[0]; + for (int i = 0; i < NUM_POOLS; i++) + if (reseedCount % (1 << i) == 0) + generator.addRandomBytes(pools[i].digest()); + lastReseed = System.currentTimeMillis(); + pool0Count = 0; + } + generator.nextBytes(buffer); + } + + public void addRandomByte(byte b) + { + pools[pool].update(b); + if (pool == 0) + pool0Count++; + pool = (pool + 1) % NUM_POOLS; + } + + public void addRandomBytes(byte[] buf, int offset, int length) + { + pools[pool].update(buf, offset, length); + if (pool == 0) + pool0Count += length; + pool = (pool + 1) % NUM_POOLS; + } + + public void addRandomEvent(RandomEvent event) + { + if (event.getPoolNumber() < 0 || event.getPoolNumber() >= pools.length) + throw new IllegalArgumentException("pool number out of range: " + + event.getPoolNumber()); + pools[event.getPoolNumber()].update(event.getSourceNumber()); + pools[event.getPoolNumber()].update((byte) event.getData().length); + pools[event.getPoolNumber()].update(event.getData()); + if (event.getPoolNumber() == 0) + pool0Count += event.getData().length; + } + + // Reading and writing this object is equivalent to storing and retrieving + // the seed. + + private void writeObject(ObjectOutputStream out) throws IOException + { + byte[] seed = new byte[SEED_FILE_SIZE]; + try + { + generator.nextBytes(seed); + } + catch (LimitReachedException shouldNeverHappen) + { + throw new Error(shouldNeverHappen); + } + out.write(seed); + } + + private void readObject(ObjectInputStream in) throws IOException + { + byte[] seed = new byte[SEED_FILE_SIZE]; + in.readFully(seed); + generator.addRandomBytes(seed); + } + + /** + * The Fortuna generator function. The generator is a PRNG in its own right; + * Fortuna itself is basically a wrapper around this generator that manages + * reseeding in a secure way. + */ + public static class Generator + extends BasePRNG + implements Cloneable + { + private static final int LIMIT = 1 << 20; + private final IBlockCipher cipher; + private final IMessageDigest hash; + private final byte[] counter; + private final byte[] key; + private boolean seeded; + + public Generator(final IBlockCipher cipher, final IMessageDigest hash) + { + super(Registry.FORTUNA_GENERATOR_PRNG); + this.cipher = cipher; + this.hash = hash; + counter = new byte[cipher.defaultBlockSize()]; + buffer = new byte[cipher.defaultBlockSize()]; + int keysize = 0; + for (Iterator it = cipher.keySizes(); it.hasNext();) + { + int ks = ((Integer) it.next()).intValue(); + if (ks > keysize) + keysize = ks; + if (keysize >= 32) + break; + } + key = new byte[keysize]; + } + + public byte nextByte() + { + byte[] b = new byte[1]; + nextBytes(b, 0, 1); + return b[0]; + } + + public void nextBytes(byte[] out, int offset, int length) + { + if (! seeded) + throw new IllegalStateException("generator not seeded"); + int count = 0; + do + { + int amount = Math.min(LIMIT, length - count); + try + { + super.nextBytes(out, offset + count, amount); + } + catch (LimitReachedException shouldNeverHappen) + { + throw new Error(shouldNeverHappen); + } + count += amount; + for (int i = 0; i < key.length; i += counter.length) + { + fillBlock(); + int l = Math.min(key.length - i, cipher.currentBlockSize()); + System.arraycopy(buffer, 0, key, i, l); + } + resetKey(); + } + while (count < length); + fillBlock(); + ndx = 0; + } + + public void addRandomByte(byte b) + { + addRandomBytes(new byte[] { b }); + } + + public void addRandomBytes(byte[] seed, int offset, int length) + { + hash.update(key); + hash.update(seed, offset, length); + byte[] newkey = hash.digest(); + System.arraycopy(newkey, 0, key, 0, Math.min(key.length, newkey.length)); + resetKey(); + incrementCounter(); + seeded = true; + } + + public void fillBlock() + { + if (! seeded) + throw new IllegalStateException("generator not seeded"); + cipher.encryptBlock(counter, 0, buffer, 0); + incrementCounter(); + } + + public void setup(Map attributes) + { + seeded = false; + Arrays.fill(key, (byte) 0); + Arrays.fill(counter, (byte) 0); + byte[] seed = (byte[]) attributes.get(SEED); + if (seed != null) + addRandomBytes(seed); + fillBlock(); + } + + /** + * Resets the cipher's key. This is done after every reseed, which combines + * the old key and the seed, and processes that throigh the hash function. + */ + private void resetKey() + { + try + { + cipher.reset(); + cipher.init(Collections.singletonMap(IBlockCipher.KEY_MATERIAL, key)); + } + // We expect to never get an exception here. + catch (InvalidKeyException ike) + { + throw new Error(ike); + } + catch (IllegalArgumentException iae) + { + throw new Error(iae); + } + } + + /** + * Increment `counter' as a sixteen-byte little-endian unsigned integer by + * one. + */ + private void incrementCounter() + { + for (int i = 0; i < counter.length; i++) + { + counter[i]++; + if (counter[i] != 0) + break; + } + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/prng/ICMGenerator.java b/libjava/classpath/gnu/javax/crypto/prng/ICMGenerator.java new file mode 100644 index 000000000..a4df5b964 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/prng/ICMGenerator.java @@ -0,0 +1,306 @@ +/* ICMGenerator.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.prng; + +import gnu.java.security.Registry; +import gnu.java.security.prng.BasePRNG; +import gnu.java.security.prng.LimitReachedException; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; + +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.util.HashMap; +import java.util.Map; + +/** + * Counter Mode is a way to define a pseudorandom keystream generator using a + * block cipher. The keystream can be used for additive encryption, key + * derivation, or any other application requiring pseudorandom data. + *

+ * In ICM, the keystream is logically broken into segments. Each segment is + * identified with a segment index, and the segments have equal lengths. This + * segmentation makes ICM especially appropriate for securing packet-based + * protocols. + *

+ * This implementation adheres to the definition of the ICM keystream generation + * function that allows for any symetric key block cipher algorithm + * (initialisation parameter gnu.crypto.prng.icm.cipher.name + * taken to be an instance of {@link java.lang.String}) to be used. If such a + * parameter is not defined/included in the initialisation Map, + * then the "Rijndael" algorithm is used. Furthermore, if the initialisation + * parameter gnu.crypto.cipher.block.size (taken to be a instance + * of {@link java.lang.Integer}) is missing or undefined in the initialisation + * Map, then the cipher's default block size is used. + *

+ * The practical limits and constraints of such generator are: + *

+ *

+ * NOTE: Rijndael is used as the default symmetric key block cipher + * algorithm because, with its default block and key sizes, it is the AES. Yet + * being Rijndael, the algorithm offers more versatile block and key sizes which + * may prove to be useful for generating longer key streams. + *

+ * References: + *

    + *
  1. + * Integer Counter Mode, David A. McGrew.
  2. + *
+ */ +public class ICMGenerator + extends BasePRNG + implements Cloneable +{ + /** Property name of underlying block cipher for this ICM generator. */ + public static final String CIPHER = "gnu.crypto.prng.icm.cipher.name"; + /** Property name of ICM's block index length. */ + public static final String BLOCK_INDEX_LENGTH = + "gnu.crypto.prng.icm.block.index.length"; + /** Property name of ICM's segment index length. */ + public static final String SEGMENT_INDEX_LENGTH = + "gnu.crypto.prng.icm.segment.index.length"; + /** Property name of ICM's offset. */ + public static final String OFFSET = "gnu.crypto.prng.icm.offset"; + /** Property name of ICM's segment index. */ + public static final String SEGMENT_INDEX = "gnu.crypto.prng.icm.segment.index"; + /** The integer value 256 as a BigInteger. */ + private static final BigInteger TWO_FIFTY_SIX = new BigInteger("256"); + /** The underlying cipher implementation. */ + private IBlockCipher cipher; + /** This keystream block index length in bytes. */ + private int blockNdxLength = -1; + /** This keystream segment index length in bytes. */ + private int segmentNdxLength = -1; + /** The index of the next block for a given keystream segment. */ + private BigInteger blockNdx = BigInteger.ZERO; + /** The segment index for this keystream. */ + private BigInteger segmentNdx; + /** The initial counter for a given keystream segment. */ + private BigInteger C0; + + /** Trivial 0-arguments constructor. */ + public ICMGenerator() + { + super(Registry.ICM_PRNG); + } + + // Conceptually, ICM is a keystream generator that takes a secret key and a + // segment index as an input and then outputs a keystream segment. The + // segmentation lends itself to packet encryption, as each keystream segment + // can be used to encrypt a distinct packet. + // + // An ICM key consists of the block cipher key and an Offset. The Offset is + // an integer with BLOCK_LENGTH octets... + public void setup(Map attributes) + { + // find out which cipher algorithm to use + boolean newCipher = true; + String underlyingCipher = (String) attributes.get(CIPHER); + if (underlyingCipher == null) + if (cipher == null) // happy birthday + // ensure we have a reliable implementation of this cipher + cipher = CipherFactory.getInstance(Registry.RIJNDAEL_CIPHER); + else + // we already have one. use it as is + newCipher = false; + else // ensure we have a reliable implementation of this cipher + cipher = CipherFactory.getInstance(underlyingCipher); + + // find out what block size we should use it in + int cipherBlockSize = 0; + Integer bs = (Integer) attributes.get(IBlockCipher.CIPHER_BLOCK_SIZE); + if (bs != null) + cipherBlockSize = bs.intValue(); + else + { + if (newCipher) // assume we'll use its default block size + cipherBlockSize = cipher.defaultBlockSize(); + // else use as is + } + // get the key material + byte[] key = (byte[]) attributes.get(IBlockCipher.KEY_MATERIAL); + if (key == null) + throw new IllegalArgumentException(IBlockCipher.KEY_MATERIAL); + // now initialise the cipher + HashMap map = new HashMap(); + if (cipherBlockSize != 0) // only needed if new or changed + map.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(cipherBlockSize)); + map.put(IBlockCipher.KEY_MATERIAL, key); + try + { + cipher.init(map); + } + catch (InvalidKeyException x) + { + throw new IllegalArgumentException(IBlockCipher.KEY_MATERIAL); + } + // at this point we have an initialised (new or otherwise) cipher + // ensure that remaining params make sense + cipherBlockSize = cipher.currentBlockSize(); + BigInteger counterRange = TWO_FIFTY_SIX.pow(cipherBlockSize); + // offset, like the underlying cipher key is not cloneable + // always look for it and throw an exception if it's not there + Object obj = attributes.get(OFFSET); + // allow either a byte[] or a BigInteger + BigInteger r; + if (obj instanceof BigInteger) + r = (BigInteger) obj; + else // assume byte[]. should be same length as cipher block size + { + byte[] offset = (byte[]) obj; + if (offset.length != cipherBlockSize) + throw new IllegalArgumentException(OFFSET); + r = new BigInteger(1, offset); + } + int wantBlockNdxLength = -1; // number of octets in the block index + Integer i = (Integer) attributes.get(BLOCK_INDEX_LENGTH); + if (i != null) + { + wantBlockNdxLength = i.intValue(); + if (wantBlockNdxLength < 1) + throw new IllegalArgumentException(BLOCK_INDEX_LENGTH); + } + int wantSegmentNdxLength = -1; // number of octets in the segment index + i = (Integer) attributes.get(SEGMENT_INDEX_LENGTH); + if (i != null) + { + wantSegmentNdxLength = i.intValue(); + if (wantSegmentNdxLength < 1) + throw new IllegalArgumentException(SEGMENT_INDEX_LENGTH); + } + // if both are undefined check if it's a reuse + if ((wantBlockNdxLength == -1) && (wantSegmentNdxLength == -1)) + { + if (blockNdxLength == -1) // new instance + throw new IllegalArgumentException(BLOCK_INDEX_LENGTH + ", " + + SEGMENT_INDEX_LENGTH); + // else reuse old values + } + else // only one is undefined, set it to BLOCK_LENGTH/2 minus the other + { + int limit = cipherBlockSize / 2; + if (wantBlockNdxLength == -1) + wantBlockNdxLength = limit - wantSegmentNdxLength; + else if (wantSegmentNdxLength == -1) + wantSegmentNdxLength = limit - wantBlockNdxLength; + else if ((wantSegmentNdxLength + wantBlockNdxLength) > limit) + throw new IllegalArgumentException(BLOCK_INDEX_LENGTH + ", " + + SEGMENT_INDEX_LENGTH); + // save new values + blockNdxLength = wantBlockNdxLength; + segmentNdxLength = wantSegmentNdxLength; + } + // get the segment index as a BigInteger + BigInteger s = (BigInteger) attributes.get(SEGMENT_INDEX); + if (s == null) + { + if (segmentNdx == null) // segment index was never set + throw new IllegalArgumentException(SEGMENT_INDEX); + // reuse; check if still valid + if (segmentNdx.compareTo(TWO_FIFTY_SIX.pow(segmentNdxLength)) > 0) + throw new IllegalArgumentException(SEGMENT_INDEX); + } + else + { + if (s.compareTo(TWO_FIFTY_SIX.pow(segmentNdxLength)) > 0) + throw new IllegalArgumentException(SEGMENT_INDEX); + segmentNdx = s; + } + // The initial counter of the keystream segment with segment index s is + // defined as follows, where r denotes the Offset: + // + // C[0] = (s * (256^BLOCK_INDEX_LENGTH) + r) modulo (256^BLOCK_LENGTH) + C0 = segmentNdx.multiply(TWO_FIFTY_SIX.pow(blockNdxLength)) + .add(r).modPow(BigInteger.ONE, counterRange); + try + { + fillBlock(); + } + catch (LimitReachedException impossible) + { + throw (InternalError) + new InternalError().initCause(impossible); + } + } + + public void fillBlock() throws LimitReachedException + { + if (C0 == null) + throw new IllegalStateException(); + if (blockNdx.compareTo(TWO_FIFTY_SIX.pow(blockNdxLength)) >= 0) + throw new LimitReachedException(); + int cipherBlockSize = cipher.currentBlockSize(); + BigInteger counterRange = TWO_FIFTY_SIX.pow(cipherBlockSize); + // encrypt the counter for the current blockNdx + // C[i] = (C[0] + i) modulo (256^BLOCK_LENGTH). + BigInteger Ci = C0.add(blockNdx).modPow(BigInteger.ONE, counterRange); + buffer = Ci.toByteArray(); + int limit = buffer.length; + if (limit < cipherBlockSize) + { + byte[] data = new byte[cipherBlockSize]; + System.arraycopy(buffer, 0, data, cipherBlockSize - limit, limit); + buffer = data; + } + else if (limit > cipherBlockSize) + { + byte[] data = new byte[cipherBlockSize]; + System.arraycopy(buffer, limit - cipherBlockSize, data, 0, + cipherBlockSize); + buffer = data; + } + cipher.encryptBlock(buffer, 0, buffer, 0); + blockNdx = blockNdx.add(BigInteger.ONE); // increment blockNdx + } +} diff --git a/libjava/classpath/gnu/javax/crypto/prng/IPBE.java b/libjava/classpath/gnu/javax/crypto/prng/IPBE.java new file mode 100644 index 000000000..8138b7b9a --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/prng/IPBE.java @@ -0,0 +1,81 @@ +/* IPBE.java -- + Copyright (C) 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.crypto.prng; + +/** + * Trivial interface to group Password-based encryption property names and + * constants. + */ +public interface IPBE +{ + /** + * Property name for the iteration count in a PBE algorithm. The property + * associated with this is expected to be an {@link Integer}. + */ + String ITERATION_COUNT = "gnu.crypto.pbe.iteration.count"; + + /** + * Property name for the password in a PBE algorithm. The property associated + * with this is expected to be a char array. + */ + String PASSWORD = "gnu.crypto.pbe.password"; + + /** + * Property name for the password character encoding in a PBE algorithm. The + * property associated with this is expected to be a String denoting a valid + * character-encoding name. If this property is not set, and a password is + * used, then {@link #DEFAULT_PASSWORD_ENCODING} will be used when converting + * the password character(s) to bytes. + */ + String PASSWORD_ENCODING = "gnu.crypto.pbe.password.encoding"; + + /** + * Property name for the salt in a PBE algorithm. The property associated + * with this is expected to be a byte array. + */ + String SALT = "gnu.crypto.pbe.salt"; + + /** + * The default character set encoding name to be used if (a) a password is + * to be used as the source for a PBE-based Key Derivation Function (KDF) and + * (b) no character set encoding name was specified among the attributes used + * to initialize the instance. + */ + String DEFAULT_PASSWORD_ENCODING = "UTF-8"; +} diff --git a/libjava/classpath/gnu/javax/crypto/prng/PBKDF2.java b/libjava/classpath/gnu/javax/crypto/prng/PBKDF2.java new file mode 100644 index 000000000..22fcd5504 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/prng/PBKDF2.java @@ -0,0 +1,184 @@ +/* PBKDF2.java -- + Copyright (C) 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.crypto.prng; + +import gnu.java.security.prng.BasePRNG; +import gnu.java.security.prng.LimitReachedException; +import gnu.javax.crypto.mac.HMac; +import gnu.javax.crypto.mac.IMac; + +import java.io.UnsupportedEncodingException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + * An implementation of the key derivation function KDF2 from PKCS #5: + * Password-Based Cryptography (PBE). This KDF is essentially a way to + * transform a password and a salt into a stream of random bytes, which may then + * be used to initialize a cipher or a MAC. + *

+ * This version uses a MAC as its pseudo-random function, and the password is + * used as the key. + *

+ * References: + *

    + *
  1. B. Kaliski, RFC 2898: + * Password-Based Cryptography Specification, Version 2.0
  2. + *
+ */ +public class PBKDF2 + extends BasePRNG + implements Cloneable +{ + /** + * The bytes fed into the MAC. This is initially the concatenation of the salt + * and the block number. + */ + private byte[] in; + /** The iteration count. */ + private int iterationCount; + /** The salt. */ + private byte[] salt; + /** The MAC (the pseudo-random function we use). */ + private IMac mac; + /** The number of hLen-sized blocks generated. */ + private long count; + + /** + * Creates a new PBKDF2 object. The argument is the MAC that will serve as the + * pseudo-random function. The MAC does not need to be initialized. + * + * @param mac The pseudo-random function. + */ + public PBKDF2(IMac mac) + { + super("PBKDF2-" + mac.name()); + this.mac = mac; + iterationCount = -1; + } + + public void setup(Map attributes) + { + Map macAttrib = new HashMap(); + macAttrib.put(HMac.USE_WITH_PKCS5_V2, Boolean.TRUE); + byte[] s = (byte[]) attributes.get(IPBE.SALT); + if (s == null) + { + if (salt == null) + throw new IllegalArgumentException("no salt specified"); + // Otherwise re-use. + } + else + salt = s; + byte[] macKeyMaterial; + char[] password = (char[]) attributes.get(IPBE.PASSWORD); + if (password != null) + { + String encoding = (String) attributes.get(IPBE.PASSWORD_ENCODING); + if (encoding == null || encoding.trim().length() == 0) + encoding = IPBE.DEFAULT_PASSWORD_ENCODING; + else + encoding = encoding.trim(); + try + { + macKeyMaterial = new String(password).getBytes(encoding); + } + catch (UnsupportedEncodingException uee) + { + throw new IllegalArgumentException("Unknown or unsupported encoding: " + + encoding, uee); + } + } + else + macKeyMaterial = (byte[]) attributes.get(IMac.MAC_KEY_MATERIAL); + + if (macKeyMaterial != null) + macAttrib.put(IMac.MAC_KEY_MATERIAL, macKeyMaterial); + else if (! initialised) + throw new IllegalArgumentException( + "Neither password nor key-material were specified"); + // otherwise re-use previous password/key-material + try + { + mac.init(macAttrib); + } + catch (Exception x) + { + throw new IllegalArgumentException(x.getMessage()); + } + Integer ic = (Integer) attributes.get(IPBE.ITERATION_COUNT); + if (ic != null) + iterationCount = ic.intValue(); + if (iterationCount <= 0) + throw new IllegalArgumentException("bad iteration count"); + count = 0L; + buffer = new byte[mac.macSize()]; + try + { + fillBlock(); + } + catch (LimitReachedException x) + { + throw new Error(x.getMessage()); + } + } + + public void fillBlock() throws LimitReachedException + { + if (++count > ((1L << 32) - 1)) + throw new LimitReachedException(); + Arrays.fill(buffer, (byte) 0x00); + int limit = salt.length; + in = new byte[limit + 4]; + System.arraycopy(salt, 0, in, 0, salt.length); + in[limit++] = (byte)(count >>> 24); + in[limit++] = (byte)(count >>> 16); + in[limit++] = (byte)(count >>> 8); + in[limit ] = (byte) count; + for (int i = 0; i < iterationCount; i++) + { + mac.reset(); + mac.update(in, 0, in.length); + in = mac.digest(); + for (int j = 0; j < buffer.length; j++) + buffer[j] ^= in[j]; + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/prng/PRNGFactory.java b/libjava/classpath/gnu/javax/crypto/prng/PRNGFactory.java new file mode 100644 index 000000000..0a7c5e377 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/prng/PRNGFactory.java @@ -0,0 +1,115 @@ +/* PRNGFactory.java -- + 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.crypto.prng; + +import gnu.java.security.Registry; +import gnu.java.security.prng.IRandom; +import gnu.javax.crypto.mac.HMacFactory; +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +/** + * A Factory to instantiate pseudo random number generators. + */ +public class PRNGFactory + implements Registry +{ + /** Trivial constructor to enforce Singleton pattern. */ + private PRNGFactory() + { + } + + /** + * Returns an instance of a padding algorithm given its name. + * + * @param prng the case-insensitive name of the PRNG. + * @return an instance of the pseudo-random number generator. + * @exception InternalError if the implementation does not pass its self- + * test. + */ + public static IRandom getInstance(String prng) + { + if (prng == null) + return null; + prng = prng.trim(); + IRandom result = null; + if (prng.equalsIgnoreCase(ARCFOUR_PRNG) || prng.equalsIgnoreCase(RC4_PRNG)) + result = new ARCFour(); + else if (prng.equalsIgnoreCase(ICM_PRNG)) + result = new ICMGenerator(); + else if (prng.equalsIgnoreCase(UMAC_PRNG)) + result = new UMacGenerator(); + else if (prng.toLowerCase().startsWith(PBKDF2_PRNG_PREFIX)) + { + String macName = prng.substring(PBKDF2_PRNG_PREFIX.length()); + IMac mac = MacFactory.getInstance(macName); + if (mac == null) + return null; + result = new PBKDF2(mac); + } + + if (result != null) + return result; + + return gnu.java.security.prng.PRNGFactory.getInstance(prng); + } + + /** + * Returns a {@link Set} of names of padding algorithms supported by this + * Factory. + * + * @return a {@link Set} of pseudo-random number generator algorithm names + * (Strings). + */ + public static Set getNames() + { + HashSet hs = new HashSet(gnu.java.security.prng.PRNGFactory.getNames()); + hs.add(ICM_PRNG); + hs.add(UMAC_PRNG); + // add all hmac implementations as candidate PBKDF2 ones too + for (Iterator it = HMacFactory.getNames().iterator(); it.hasNext();) + hs.add(PBKDF2_PRNG_PREFIX + ((String) it.next())); + return Collections.unmodifiableSet(hs); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/prng/UMacGenerator.java b/libjava/classpath/gnu/javax/crypto/prng/UMacGenerator.java new file mode 100644 index 000000000..1ee449223 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/prng/UMacGenerator.java @@ -0,0 +1,186 @@ +/* UMacGenerator.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.prng; + +import gnu.java.security.Registry; +import gnu.java.security.prng.BasePRNG; +import gnu.java.security.prng.LimitReachedException; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.security.InvalidKeyException; + +/** + * KDFs (Key Derivation Functions) are used to stretch user-supplied key + * material to specific size(s) required by high level cryptographic primitives. + * Described in the UMAC + * paper, this function basically operates an underlying symmetric key block + * cipher instance in output feedback mode (OFB), as a strong + * pseudo-random number generator. + *

+ * UMacGenerator requires an index parameter + * (initialisation parameter gnu.crypto.prng.umac.kdf.index taken + * to be an instance of {@link Integer} with a value between 0 and + * 255). Using the same key, but different indices, generates + * different pseudorandom outputs. + *

+ * This implementation generalises the definition of the + * UmacGenerator algorithm to allow for other than the AES + * symetric key block cipher algorithm (initialisation parameter + * gnu.crypto.prng.umac.cipher.name taken to be an instance of + * {@link String}). If such a parameter is not defined/included in the + * initialisation Map, then the "Rijndael" algorithm is used. + * Furthermore, if the initialisation parameter + * gnu.crypto.cipher.block.size (taken to be a instance of + * {@link Integer}) is missing or undefined in the initialisation + * Map, then the cipher's default block size is used. + *

+ * NOTE: Rijndael is used as the default symmetric key block cipher + * algorithm because, with its default block and key sizes, it is the AES. Yet + * being Rijndael, the algorithm offers more versatile block and key sizes which + * may prove to be useful for generating "longer" key streams. + *

+ * References: + *

    + *
  1. + * UMAC: Message Authentication Code using Universal Hashing.
    + * T. Krovetz, J. Black, S. Halevi, A. Hevia, H. Krawczyk, and P. Rogaway.
  2. + *
+ */ +public class UMacGenerator + extends BasePRNG + implements Cloneable +{ + /** + * Property name of the KDF index value to use in this + * instance. The value is taken to be an {@link Integer} less than + * 256. + */ + public static final String INDEX = "gnu.crypto.prng.umac.index"; + /** The name of the underlying symmetric key block cipher algorithm. */ + public static final String CIPHER = "gnu.crypto.prng.umac.cipher.name"; + /** The generator's underlying block cipher. */ + private IBlockCipher cipher; + + /** Trivial 0-arguments constructor. */ + public UMacGenerator() + { + super(Registry.UMAC_PRNG); + } + + public void setup(Map attributes) + { + boolean newCipher = true; + String cipherName = (String) attributes.get(CIPHER); + if (cipherName == null) + if (cipher == null) // happy birthday + cipher = CipherFactory.getInstance(Registry.RIJNDAEL_CIPHER); + else // we already have one. use it as is + newCipher = false; + else + cipher = CipherFactory.getInstance(cipherName); + // find out what block size we should use it in + int cipherBlockSize = 0; + Integer bs = (Integer) attributes.get(IBlockCipher.CIPHER_BLOCK_SIZE); + if (bs != null) + cipherBlockSize = bs.intValue(); + else + { + if (newCipher) // assume we'll use its default block size + cipherBlockSize = cipher.defaultBlockSize(); + // else use as is + } + // get the key material + byte[] key = (byte[]) attributes.get(IBlockCipher.KEY_MATERIAL); + if (key == null) + throw new IllegalArgumentException(IBlockCipher.KEY_MATERIAL); + + int keyLength = key.length; + // ensure that keyLength is valid for the chosen underlying cipher + boolean ok = false; + for (Iterator it = cipher.keySizes(); it.hasNext();) + { + ok = (keyLength == ((Integer) it.next()).intValue()); + if (ok) + break; + } + if (! ok) + throw new IllegalArgumentException("key length"); + // ensure that remaining params make sense + int index = -1; + Integer i = (Integer) attributes.get(INDEX); + if (i != null) + { + index = i.intValue(); + if (index < 0 || index > 255) + throw new IllegalArgumentException(INDEX); + } + // now initialise the underlying cipher + Map map = new HashMap(); + if (cipherBlockSize != 0) // only needed if new or changed + map.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(cipherBlockSize)); + map.put(IBlockCipher.KEY_MATERIAL, key); + try + { + cipher.init(map); + } + catch (InvalidKeyException x) + { + throw new IllegalArgumentException(IBlockCipher.KEY_MATERIAL); + } + buffer = new byte[cipher.currentBlockSize()]; + buffer[cipher.currentBlockSize() - 1] = (byte) index; + try + { + fillBlock(); + } + catch (LimitReachedException impossible) + { + } + } + + public void fillBlock() throws LimitReachedException + { + cipher.encryptBlock(buffer, 0, buffer, 0); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/AuthInfo.java b/libjava/classpath/gnu/javax/crypto/sasl/AuthInfo.java new file mode 100644 index 000000000..37c1e0852 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/AuthInfo.java @@ -0,0 +1,129 @@ +/* AuthInfo.java -- + Copyright (C) 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.crypto.sasl; + +import gnu.java.security.Registry; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.StringTokenizer; + +/** + * A static class for creating {@link IAuthInfoProvider} providers. It + * transparently locates and uses any provider instances, based on the value + * assigned to the System property with the key + * gnu.crypto.sasl.auth.info.provider.pkgs. If more than one is + * specified they SHOULD be separated with a vertical bar character. Please note + * that the GNU provider is always added last to the list, disregarding whether + * it was mentioned or not in the value of that property, or if it that property + * was not defined. + */ +public class AuthInfo +{ + private static final ArrayList factories = new ArrayList(); + static + { + IAuthInfoProviderFactory ours = new AuthInfoProviderFactory(); + // if SASL_AUTH_INFO_PROVIDER_PKGS is defined then parse it + String clazz; + String pkgs = System.getProperty(Registry.SASL_AUTH_INFO_PROVIDER_PKGS, + null); + if (pkgs != null) + { + for (StringTokenizer st = new StringTokenizer(pkgs, "|"); st.hasMoreTokens();) + { + clazz = st.nextToken().trim(); + if (! "gnu.javax.crypto.sasl".equals(clazz)) + { + clazz += ".AuthInfoProviderFactory"; + try + { + IAuthInfoProviderFactory factory = + (IAuthInfoProviderFactory) Class.forName(clazz).newInstance(); + factories.add(factory); + } + catch (ClassCastException ignored) + { + } + catch (ClassNotFoundException ignored) + { + } + catch (InstantiationException ignored) + { + } + catch (IllegalAccessException ignored) + { + } + } + } + } + // always add ours last; unless it's already there + if (!factories.contains(ours)) + factories.add(ours); + } + + /** Trivial constructor to enforce Singleton pattern. */ + private AuthInfo() + { + super(); + } + + /** + * A convenience method to return the authentication information provider for + * a designated SASL mechnanism. It goes through all the installed provider + * factories, one at a time, and attempts to return a new instance of the + * provider for the designated mechanism. It stops at the first factory + * returning a non-null provider. + * + * @param mechanism the name of a SASL mechanism. + * @return an implementation that provides {@link IAuthInfoProvider} for that + * mechanism; or null if none found. + */ + public static IAuthInfoProvider getProvider(String mechanism) + { + for (Iterator it = factories.iterator(); it.hasNext();) + { + IAuthInfoProviderFactory factory = (IAuthInfoProviderFactory) it.next(); + IAuthInfoProvider result = factory.getInstance(mechanism); + if (result != null) + return result; + } + return null; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/AuthInfoProviderFactory.java b/libjava/classpath/gnu/javax/crypto/sasl/AuthInfoProviderFactory.java new file mode 100644 index 000000000..f881e6e11 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/AuthInfoProviderFactory.java @@ -0,0 +1,67 @@ +/* AuthInfoProviderFactory.java -- + Copyright (C) 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.crypto.sasl; + +import gnu.java.security.Registry; +import gnu.javax.crypto.sasl.crammd5.CramMD5AuthInfoProvider; +import gnu.javax.crypto.sasl.plain.PlainAuthInfoProvider; +import gnu.javax.crypto.sasl.srp.SRPAuthInfoProvider; + +/** + * The concrete SASL authentication information provider factory. + */ +public class AuthInfoProviderFactory + implements IAuthInfoProviderFactory +{ + // implicit 0-args constructor + + public IAuthInfoProvider getInstance(String mechanism) + { + if (mechanism == null) + return null; + mechanism = mechanism.trim().toUpperCase(); + if (mechanism.startsWith(Registry.SASL_SRP_MECHANISM)) + return new SRPAuthInfoProvider(); + if (mechanism.equals(Registry.SASL_CRAM_MD5_MECHANISM)) + return new CramMD5AuthInfoProvider(); + if (mechanism.equals(Registry.SASL_PLAIN_MECHANISM)) + return new PlainAuthInfoProvider(); + return null; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/ClientFactory.java b/libjava/classpath/gnu/javax/crypto/sasl/ClientFactory.java new file mode 100644 index 000000000..30309d2c7 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/ClientFactory.java @@ -0,0 +1,168 @@ +/* ClientFactory.java -- + Copyright (C) 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.crypto.sasl; + +import gnu.java.security.Registry; +import gnu.javax.crypto.sasl.anonymous.AnonymousClient; +import gnu.javax.crypto.sasl.crammd5.CramMD5Client; +import gnu.javax.crypto.sasl.plain.PlainClient; +import gnu.javax.crypto.sasl.srp.SRPClient; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslClientFactory; +import javax.security.sasl.SaslException; + +/** + * The implementation of {@link SaslClientFactory}. + */ +public class ClientFactory + implements SaslClientFactory +{ + // implicit 0-arguments constructor + + public static final Set getNames() + { + return Collections.unmodifiableSet(new HashSet(Arrays.asList(getNamesInternal(null)))); + } + + private static final String[] getNamesInternal(Map props) + { + String[] all = new String[] { + Registry.SASL_SRP_MECHANISM, + Registry.SASL_CRAM_MD5_MECHANISM, + Registry.SASL_PLAIN_MECHANISM, + Registry.SASL_ANONYMOUS_MECHANISM }; + if (props == null) + return all; + if (hasPolicy(Sasl.POLICY_PASS_CREDENTIALS, props)) + return new String[0]; + List result = new ArrayList(all.length); + for (int i = 0; i < all.length;) + result.add(all[i++]); + if (hasPolicy(Sasl.POLICY_NOPLAINTEXT, props)) + result.remove(Registry.SASL_PLAIN_MECHANISM); + if (hasPolicy(Sasl.POLICY_NOACTIVE, props)) + { + result.remove(Registry.SASL_CRAM_MD5_MECHANISM); + result.remove(Registry.SASL_PLAIN_MECHANISM); + } + if (hasPolicy(Sasl.POLICY_NODICTIONARY, props)) + { + result.remove(Registry.SASL_CRAM_MD5_MECHANISM); + result.remove(Registry.SASL_PLAIN_MECHANISM); + } + if (hasPolicy(Sasl.POLICY_NOANONYMOUS, props)) + { + result.remove(Registry.SASL_ANONYMOUS_MECHANISM); + } + if (hasPolicy(Sasl.POLICY_FORWARD_SECRECY, props)) + { + result.remove(Registry.SASL_CRAM_MD5_MECHANISM); + result.remove(Registry.SASL_ANONYMOUS_MECHANISM); + result.remove(Registry.SASL_PLAIN_MECHANISM); + } + return (String[]) result.toArray(new String[0]); + } + + public static final ClientMechanism getInstance(String mechanism) + { + if (mechanism == null) + return null; + mechanism = mechanism.trim().toUpperCase(); + if (mechanism.equals(Registry.SASL_SRP_MECHANISM)) + return new SRPClient(); + if (mechanism.equals(Registry.SASL_CRAM_MD5_MECHANISM)) + return new CramMD5Client(); + if (mechanism.equals(Registry.SASL_PLAIN_MECHANISM)) + return new PlainClient(); + if (mechanism.equals(Registry.SASL_ANONYMOUS_MECHANISM)) + return new AnonymousClient(); + return null; + } + + public SaslClient createSaslClient(String[] mechanisms, + String authorisationID, String protocol, + String serverName, Map props, + CallbackHandler cbh) throws SaslException + { + ClientMechanism result = null; + String mechanism; + for (int i = 0; i < mechanisms.length; i++) + { + mechanism = mechanisms[i]; + result = getInstance(mechanism); + if (result != null) + break; + } + if (result != null) + { + HashMap attributes = new HashMap(); + if (props != null) + attributes.putAll(props); + attributes.put(Registry.SASL_AUTHORISATION_ID, authorisationID); + attributes.put(Registry.SASL_PROTOCOL, protocol); + attributes.put(Registry.SASL_SERVER_NAME, serverName); + attributes.put(Registry.SASL_CALLBACK_HANDLER, cbh); + result.init(attributes); + return result; + } + throw new SaslException("No supported mechanism found in given mechanism list"); + } + + public String[] getMechanismNames(Map props) + { + return getNamesInternal(props); + } + + private static boolean hasPolicy(String propertyName, Map props) + { + return "true".equalsIgnoreCase(String.valueOf(props.get(propertyName))); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/ClientMechanism.java b/libjava/classpath/gnu/javax/crypto/sasl/ClientMechanism.java new file mode 100644 index 000000000..5e0dcd096 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/ClientMechanism.java @@ -0,0 +1,293 @@ +/* ClientMechanism.java -- + Copyright (C) 2003, 2005, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.sasl; + +import gnu.java.security.Registry; + +import java.util.HashMap; +import java.util.Map; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslException; + +/** + * A base class to facilitate implementing SASL client-side mechanisms. + */ +public abstract class ClientMechanism + implements SaslClient +{ + /** Name of this mechanism. */ + protected String mechanism; + /** The authorisation identity. */ + protected String authorizationID; + /** Name of protocol using this mechanism. */ + protected String protocol; + /** Name of server to authenticate to. */ + protected String serverName; + /** Properties of qualities desired for this mechanism. */ + protected Map properties; + /** Callback handler to use with this mechanism instance. */ + protected CallbackHandler handler; + /** Channel binding data to use with this mechanism instance. */ + protected byte[] channelBinding; + /** Whether authentication phase is completed (true) or not (false). */ + protected boolean complete = false; + /** The state of the authentication automaton. */ + protected int state = -1; + + protected ClientMechanism(final String mechanism) + { + super(); + + this.mechanism = mechanism; + this.state = -1; + } + + protected abstract void initMechanism() throws SaslException; + + protected abstract void resetMechanism() throws SaslException; + + public abstract byte[] evaluateChallenge(byte[] challenge) + throws SaslException; + + public abstract boolean hasInitialResponse(); + + public boolean isComplete() + { + return complete; + } + + public byte[] unwrap(final byte[] incoming, final int offset, final int len) + throws SaslException + { + if (! isComplete()) + throw new IllegalMechanismStateException(); + return this.engineUnwrap(incoming, offset, len); + } + + public byte[] wrap(final byte[] outgoing, final int offset, final int len) + throws SaslException + { + if (! isComplete()) + throw new IllegalMechanismStateException(); + return this.engineWrap(outgoing, offset, len); + } + + public String getMechanismName() + { + return mechanism; + } + + public Object getNegotiatedProperty(final String propName) + { + if (! isComplete()) + throw new IllegalStateException(); + if (Sasl.QOP.equals(propName)) + return getNegotiatedQOP(); + if (Sasl.STRENGTH.equals(propName)) + return getNegotiatedStrength(); + if (Sasl.SERVER_AUTH.equals(propName)) + return getNegotiatedServerAuth(); + if (Sasl.MAX_BUFFER.equals(propName)) + return getNegotiatedMaxBuffer(); + if (Sasl.RAW_SEND_SIZE.equals(propName)) + return getNegotiatedRawSendSize(); + if (Sasl.POLICY_NOPLAINTEXT.equals(propName)) + return getNegotiatedPolicyNoPlainText(); + if (Sasl.POLICY_NOACTIVE.equals(propName)) + return getNegotiatedPolicyNoActive(); + if (Sasl.POLICY_NODICTIONARY.equals(propName)) + return getNegotiatedPolicyNoDictionary(); + if (Sasl.POLICY_NOANONYMOUS.equals(propName)) + return getNegotiatedPolicyNoAnonymous(); + if (Sasl.POLICY_FORWARD_SECRECY.equals(propName)) + return getNegotiatedPolicyForwardSecrecy(); + if (Sasl.POLICY_PASS_CREDENTIALS.equals(propName)) + return getNegotiatedPolicyPassCredentials(); + if (Sasl.REUSE.equals(propName)) + return getReuse(); + return null; + } + + public void dispose() throws SaslException + { + } + + public String getAuthorizationID() + { + return authorizationID; + } + + protected String getNegotiatedQOP() + { + return Registry.QOP_AUTH; + } + + protected String getNegotiatedStrength() + { + return Registry.STRENGTH_LOW; + } + + protected String getNegotiatedServerAuth() + { + return Registry.SERVER_AUTH_FALSE; + } + + protected String getNegotiatedMaxBuffer() + { + return null; + } + + protected String getNegotiatedRawSendSize() + { + return String.valueOf(Registry.SASL_BUFFER_MAX_LIMIT); + } + + protected String getNegotiatedPolicyNoPlainText() + { + return null; + } + + protected String getNegotiatedPolicyNoActive() + { + return null; + } + + protected String getNegotiatedPolicyNoDictionary() + { + return null; + } + + protected String getNegotiatedPolicyNoAnonymous() + { + return null; + } + + protected String getNegotiatedPolicyForwardSecrecy() + { + return null; + } + + protected String getNegotiatedPolicyPassCredentials() + { + return null; + } + + protected String getReuse() + { + return Registry.REUSE_FALSE; + } + + protected byte[] engineUnwrap(final byte[] incoming, final int offset, + final int len) throws SaslException + { + final byte[] result = new byte[len]; + System.arraycopy(incoming, offset, result, 0, len); + return result; + } + + protected byte[] engineWrap(final byte[] outgoing, final int offset, + final int len) throws SaslException + { + final byte[] result = new byte[len]; + System.arraycopy(outgoing, offset, result, 0, len); + return result; + } + + /** + * Initialises the mechanism with designated attributes. Permissible names and + * values are mechanism specific. + * + * @param attributes a set of name-value pairs that describes the desired + * future behaviour of this instance. + * @throws IllegalMechanismStateException if the instance is already + * initialised. + * @throws SaslException if an exception occurs during the process. + */ + public void init(final Map attributes) throws SaslException + { + if (state != -1) + throw new IllegalMechanismStateException("init()"); + if (properties == null) + properties = new HashMap(); + else + properties.clear(); + if (attributes != null) + { + authorizationID = (String) attributes.get(Registry.SASL_AUTHORISATION_ID); + protocol = (String) attributes.get(Registry.SASL_PROTOCOL); + serverName = (String) attributes.get(Registry.SASL_SERVER_NAME); + handler = (CallbackHandler) attributes.get(Registry.SASL_CALLBACK_HANDLER); + channelBinding = (byte[]) attributes.get(Registry.SASL_CHANNEL_BINDING); + properties.putAll(attributes); + } + else + handler = null; + + if (authorizationID == null) + authorizationID = ""; + if (protocol == null) + protocol = ""; + if (serverName == null) + serverName = ""; + if (channelBinding == null) + channelBinding = new byte[0]; + initMechanism(); + complete = false; + state = 0; + } + + /** + * Resets the mechanism instance for re-initialisation and use with other + * characteristics. + * + * @throws SaslException if an exception occurs during the process. + */ + public void reset() throws SaslException + { + resetMechanism(); + properties.clear(); + authorizationID = protocol = serverName = null; + channelBinding = null; + complete = false; + state = -1; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/ConfidentialityException.java b/libjava/classpath/gnu/javax/crypto/sasl/ConfidentialityException.java new file mode 100644 index 000000000..85bd2ae18 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/ConfidentialityException.java @@ -0,0 +1,82 @@ +/* ConfidentialityException.java -- + Copyright (C) 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.crypto.sasl; + +import javax.security.sasl.SaslException; + +/** + * Used by mechanisms that offer a security services layer, this checked + * exception is thrown to indicate that a violation has occured during the + * processing of a confidentiality protection filter. + */ +public class ConfidentialityException + extends SaslException +{ + /** + * Constructs a new instance of ConfidentialityException with + * no detail message. + */ + public ConfidentialityException() + { + super(); + } + + /** + * Constructs a new instance of ConfidentialityException with + * the specified detail message. + * + * @param s the detail message. + */ + public ConfidentialityException(String s) + { + super(s); + } + + /** + * Constructs a new instance of ConfidentialityException with a + * detailed message and a root exception. + * + * @param s possibly null additional detail about the exception. + * @param x a possibly null root exception that caused this one. + */ + public ConfidentialityException(String s, Throwable x) + { + super(s, x); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/IAuthInfoProvider.java b/libjava/classpath/gnu/javax/crypto/sasl/IAuthInfoProvider.java new file mode 100644 index 000000000..88acc2d0a --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/IAuthInfoProvider.java @@ -0,0 +1,116 @@ +/* IAuthInfoProvider.java -- + Copyright (C) 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.crypto.sasl; + +import java.util.Map; + +import javax.security.sasl.AuthenticationException; + +/** + * The visible methods of any authentication information provider. + */ +public interface IAuthInfoProvider +{ + /** + * Activates (initialises) this provider instance. SHOULD be the first method + * invoked on the provider. + * + * @param context a collection of name-value bindings describing the + * activation context. + * @throws AuthenticationException if an exception occurs during the + * operation. + */ + void activate(Map context) throws AuthenticationException; + + /** + * Passivates (releases) this provider instance. SHOULD be the last method + * invoked on the provider. Once it is done, no other method may be invoked on + * the same instance before it is activated agains. + * + * @throws AuthenticationException if an exception occurs during the + * operation. + */ + void passivate() throws AuthenticationException; + + /** + * Checks if a user with a designated name is known to this provider. + * + * @param userName the name of a user to check. + * @return true if the user with the designated name is known + * to this provider; false otherwise. + * @throws AuthenticationException if an exception occurs during the + * operation. + */ + boolean contains(String userName) throws AuthenticationException; + + /** + * Returns a collection of information about a designated user. The contents + * of the returned map is provider-specific of name-to-value mappings. + * + * @param userID a map of name-to-value bindings that fully describe a user. + * @return a collection of information about the designated user. + * @throws AuthenticationException if an exception occurs during the + * operation. + */ + Map lookup(Map userID) throws AuthenticationException; + + /** + * Updates the credentials of a designated user. + * + * @param userCredentials a map of name-to-value bindings that fully describe + * a user, including per new credentials. + * @throws AuthenticationException if an exception occurs during the + * operation. + */ + void update(Map userCredentials) throws AuthenticationException; + + /** + * A provider may operate in more than mode; e.g. SRP-II caters for user + * credentials computed in more than one message digest algorithm. This method + * returns the set of name-to-value bindings describing the mode of the + * provider. + * + * @param mode a unique identifier describing the operational mode. + * @return a collection of name-to-value bindings describing the designated + * mode. + * @throws AuthenticationException if an exception occurs during the + * operation. + */ + Map getConfiguration(String mode) throws AuthenticationException; +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/IAuthInfoProviderFactory.java b/libjava/classpath/gnu/javax/crypto/sasl/IAuthInfoProviderFactory.java new file mode 100644 index 000000000..2a0b5bfec --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/IAuthInfoProviderFactory.java @@ -0,0 +1,55 @@ +/* IAuthInfoProviderFactory.java -- + Copyright (C) 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.crypto.sasl; + +/** + * The visible method of every authentication information provider factory. + */ +public interface IAuthInfoProviderFactory +{ + /** + * Returns an implementation of a provider for a designated mechanism capable + * of honouring {@link IAuthInfoProvider} requests. + * + * @param mechanism the unique name of a mechanism. + * @return an implementation of {@link IAuthInfoProvider} for that mechanism + * or null if none found. + */ + IAuthInfoProvider getInstance(String mechanism); +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/IllegalMechanismStateException.java b/libjava/classpath/gnu/javax/crypto/sasl/IllegalMechanismStateException.java new file mode 100644 index 000000000..fade7792c --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/IllegalMechanismStateException.java @@ -0,0 +1,84 @@ +/* IllegalMechanismStateException.java -- + Copyright (C) 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.crypto.sasl; + +import javax.security.sasl.AuthenticationException; + +/** + * A checked exception thrown to indicate that an operation that should be + * invoked on a completed mechanism was invoked but the authentication phase of + * that mechanism was not completed yet, or that an operation that should be + * invoked on incomplete mechanisms was invoked but the authentication phase of + * that mechanism was already completed. + */ +public class IllegalMechanismStateException + extends AuthenticationException +{ + /** + * Constructs a new instance of IllegalMechanismStateException + * with no detail message. + */ + public IllegalMechanismStateException() + { + super(); + } + + /** + * Constructs a new instance of IllegalMechanismStateException + * with the specified detail message. + * + * @param detail the detail message. + */ + public IllegalMechanismStateException(String detail) + { + super(detail); + } + + /** + * Constructs a new instance of IllegalMechanismStateException + * with the specified detail message, and cause. + * + * @param detail the detail message. + * @param ex the original cause. + */ + public IllegalMechanismStateException(String detail, Throwable ex) + { + super(detail, ex); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/InputBuffer.java b/libjava/classpath/gnu/javax/crypto/sasl/InputBuffer.java new file mode 100644 index 000000000..f15205765 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/InputBuffer.java @@ -0,0 +1,272 @@ +/* InputBuffer.java -- + Copyright (C) 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.crypto.sasl; + +import gnu.java.security.Registry; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.math.BigInteger; + +/** + * The implementation of an incoming SASL buffer. + *

+ * The data elements this class caters for are described in [1]. + *

+ * References: + *

    + *
  1. + * Secure Remote Password Authentication Mechanism;
    + * draft-burdis-cat-srp-sasl-09,
    Keith Burdis and Raïf S. Naffah.
  2. + *
+ */ +public class InputBuffer +{ + /** The internal buffer stream containing the buffer's contents. */ + protected ByteArrayInputStream in; + /** The length of the buffer, according to its header. */ + protected int length; + + /** + * Constructs a SASL buffer given the buffer's encoded form, including its + * header bytes. + * + * @param frame the encoded form, including the header bytes, of a SASL + * buffer. + * @throws SaslEncodingException if the buffer is malformed. + */ + public InputBuffer(byte[] frame) throws SaslEncodingException + { + this(); + + if (frame.length < 4) + throw new SaslEncodingException("SASL buffer header too short"); + length = (frame[0] & 0xFF) << 24 + | (frame[1] & 0xFF) << 16 + | (frame[2] & 0xFF) << 8 + | (frame[3] & 0xFF); + if (length > Registry.SASL_BUFFER_MAX_LIMIT || length < 0) + throw new SaslEncodingException("SASL buffer size limit exceeded"); + in = new ByteArrayInputStream(frame, 4, length); + } + + /** Trivial private constructor for use by the class method. */ + private InputBuffer() + { + super(); + } + + /** + * Returns an instance of a SASL buffer given the buffer's encoded contents, + * excluding the buffer's header bytes. + *

+ * Calls the method with the same name and three arguments as: + * getInstance(raw, 0, raw.length). + * + * @param raw the encoded form, excluding the header bytes, of a SASL buffer. + * @return a new instance of {@link InputBuffer}. + */ + public static InputBuffer getInstance(byte[] raw) + { + return getInstance(raw, 0, raw.length); + } + + /** + * Returns an instance of a SASL buffer given the buffer's encoded contents, + * excluding the buffer's header bytes. + * + * @param raw the encoded form, excluding the header bytes, of a SASL buffer. + * @param offset offset where to start using raw bytes from. + * @param len number of bytes to use. + * @return a new instance of {@link InputBuffer}. + */ + public static InputBuffer getInstance(byte[] raw, int offset, int len) + { + InputBuffer result = new InputBuffer(); + result.in = new ByteArrayInputStream(raw, offset, len); + return result; + } + + /** + * Converts two octets into the number that they represent. + * + * @param b the two octets. + * @return the length. + */ + public static int twoBytesToLength(byte[] b) throws SaslEncodingException + { + final int result = (b[0] & 0xFF) << 8 | (b[1] & 0xFF); + if (result > Registry.SASL_TWO_BYTE_MAX_LIMIT) + throw new SaslEncodingException("SASL MPI/Text size limit exceeded"); + return result; + } + + public boolean hasMoreElements() + { + return (in.available() > 0); + } + + /** + * Decodes a SASL scalar quantity, count-octet long, from the + * current buffer. + * + * @param count the number of octets of this scalar quantity. + * @return a native representation of a SASL scalar (unsigned integer) + * quantity. + * @throws SaslEncodingException if an encoding exception occurs during the + * operation. + * @throws IOException if any other I/O exception occurs during the operation. + */ + public long getScalar(int count) throws IOException + { + if (count < 0 || count > 4) + throw new SaslEncodingException("Invalid SASL scalar octet count: " + + String.valueOf(count)); + if (! hasMoreElements()) + throw new SaslEncodingException("Not enough bytes for a scalar in buffer"); + if (in.available() < count) + throw new SaslEncodingException("Illegal SASL scalar encoding"); + byte[] element = new byte[count]; + in.read(element); + long result = 0L; + for (int i = 0; i < count; i++) + { + result <<= 8; + result |= element[i] & 0xFFL; + } + return result; + } + + /** + * Decodes a SASL OS from the current buffer. + * + * @return a native representation of a SASL OS. + * @throws SaslEncodingException if an encoding exception occurs during the + * operation. + * @throws IOException if any other I/O exception occurs during the operation. + */ + public byte[] getOS() throws IOException + { + if (! hasMoreElements()) + throw new SaslEncodingException( + "Not enough bytes for an octet-sequence in buffer"); + final int elementLength = in.read(); + if (elementLength > Registry.SASL_ONE_BYTE_MAX_LIMIT) + throw new SaslEncodingException("SASL octet-sequence size limit exceeded"); + if (in.available() < elementLength) + throw new SaslEncodingException("Illegal SASL octet-sequence encoding"); + byte[] result = new byte[elementLength]; + in.read(result); + return result; + } + + /** + * Decodes a SASL EOS from the current buffer. + * + * @return a native representation of a SASL EOS. + * @throws SaslEncodingException if an encoding exception occurs during the + * operation. + * @throws IOException if any other I/O exception occurs during the operation. + */ + public byte[] getEOS() throws IOException + { + if (in.available() < 2) + throw new SaslEncodingException( + "Not enough bytes for an extended octet-sequence in buffer"); + byte[] elementLengthBytes = new byte[2]; + in.read(elementLengthBytes); + final int elementLength = twoBytesToLength(elementLengthBytes); + if (in.available() < elementLength) + throw new SaslEncodingException( + "Illegal SASL extended octet-sequence encoding"); + byte[] result = new byte[elementLength]; + in.read(result); + return result; + } + + /** + * Decodes a SASL MPI from the current buffer. + * + * @return a native representation of a SASL MPI. + * @throws SaslEncodingException if an encoding exception occurs during the + * operation. + * @throws IOException if any other I/O exception occurs during the operation. + */ + public BigInteger getMPI() throws IOException + { + if (in.available() < 2) + throw new SaslEncodingException("Not enough bytes for an MPI in buffer"); + byte[] elementLengthBytes = new byte[2]; + in.read(elementLengthBytes); + final int elementLength = twoBytesToLength(elementLengthBytes); + if (in.available() < elementLength) + throw new SaslEncodingException( + "Illegal SASL multi-precision integer encoding"); + byte[] element = new byte[elementLength]; + in.read(element); + return new BigInteger(1, element); + } + + /** + * Decodes a SASL Text from the current buffer. + * + * @return a native representation of a SASL Text. + * @throws SaslEncodingException if an encoding exception occurs during the + * operation. + * @throws SaslEncodingException if the UTF-8 character encoding is not + * supported on this platform. + * @throws IOException if any other I/O exception occurs during the operation. + */ + public String getText() throws IOException + { + if (in.available() < 2) + throw new SaslEncodingException("Not enough bytes for a text in buffer"); + byte[] elementLengthBytes = new byte[2]; + in.read(elementLengthBytes); + final int elementLength = twoBytesToLength(elementLengthBytes); + if (in.available() < elementLength) + throw new SaslEncodingException("Illegal SASL text encoding"); + byte[] element = new byte[elementLength]; + in.read(element); + return new String(element, "UTF8"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/IntegrityException.java b/libjava/classpath/gnu/javax/crypto/sasl/IntegrityException.java new file mode 100644 index 000000000..ce1b359de --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/IntegrityException.java @@ -0,0 +1,83 @@ +/* IntegrityException.java -- + Copyright (C) 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.crypto.sasl; + +import javax.security.sasl.SaslException; + +/** + * Used by mechanisms that offer a security services layer, this checked + * exception is thrown to indicate that a violation has occured during the + * processing of an integrity protection filter, including replay + * detection. + */ +public class IntegrityException + extends SaslException +{ + /** + * Constructs a new instance of IntegrityException with no + * detail message. + */ + public IntegrityException() + { + super(); + } + + /** + * Constructs a new instance of IntegrityException with the + * specified detail message. + * + * @param s the detail message. + */ + public IntegrityException(String s) + { + super(s); + } + + /** + * Constructs a new instance of IntegrityException with a + * detailed message and a root exception. + * + * @param s possibly null additional detail about the exception. + * @param x a possibly null root exception that caused this one. + */ + public IntegrityException(String s, Throwable x) + { + super(s, x); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/NoSuchMechanismException.java b/libjava/classpath/gnu/javax/crypto/sasl/NoSuchMechanismException.java new file mode 100644 index 000000000..d22bff894 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/NoSuchMechanismException.java @@ -0,0 +1,62 @@ +/* NoSuchMechanismException.java -- + Copyright (C) 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.crypto.sasl; + +import javax.security.sasl.SaslException; + +/** + * A checked exception thrown to indicate that a designated SASL mechanism + * implementation was not found. + */ +public class NoSuchMechanismException + extends SaslException +{ + /** + * Constructs a NoSuchMechanismException with the specified + * detail message. In the case of this exception, the detail message + * designates the offending mechanism name. + * + * @param arg the detail message, which in this case is the offending + * mechanism name. + */ + public NoSuchMechanismException(String arg) + { + super(arg); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/NoSuchUserException.java b/libjava/classpath/gnu/javax/crypto/sasl/NoSuchUserException.java new file mode 100644 index 000000000..447c7b919 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/NoSuchUserException.java @@ -0,0 +1,67 @@ +/* NoSuchUserException.java -- + Copyright (C) 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.crypto.sasl; + +import javax.security.sasl.AuthenticationException; + +/** + * A checked exception thrown to indicate that a designated user is unknown to + * the authentication layer. + */ +public class NoSuchUserException + extends AuthenticationException +{ + /** Constructs a NoSuchUserException with no detail message. */ + public NoSuchUserException() + { + super(); + } + + /** + * Constructs a NoSuchUserException with the specified detail + * message. In the case of this exception, the detail message designates the + * offending username. + * + * @param arg the detail message, which in this case is the username. + */ + public NoSuchUserException(String arg) + { + super(arg); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/OutputBuffer.java b/libjava/classpath/gnu/javax/crypto/sasl/OutputBuffer.java new file mode 100644 index 000000000..4bb3b0ec2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/OutputBuffer.java @@ -0,0 +1,198 @@ +/* OutputBuffer.java -- + Copyright (C) 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.crypto.sasl; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; + +/** + * The implementation of an outgoing SASL buffer. + *

+ * The data elements this class caters for are described in [1]. + *

+ * References: + *

    + *
  1. + * Secure Remote Password Authentication Mechanism;
    + * draft-burdis-cat-srp-sasl-09,
    Keith Burdis and Raïf S. Naffah.
  2. + *
+ */ +public class OutputBuffer +{ + /** The internal output stream. */ + private ByteArrayOutputStream out; + + public OutputBuffer() + { + super(); + + out = new ByteArrayOutputStream(); + } + + /** + * Encodes a SASL scalar quantity, count-octet long, to the + * current buffer. + * + * @param count number of octets to encode b with. + * @param b the scalar quantity. + * @throws SaslEncodingException if an encoding size constraint is violated. + * @throws IOException if any other I/O exception occurs during the operation. + */ + public void setScalar(int count, int b) throws IOException + { + if (count < 0 || count > 4) + throw new SaslEncodingException("Invalid SASL scalar octet count: " + + String.valueOf(count)); + byte[] element = new byte[count]; + for (int i = count; --i >= 0; b >>>= 8) + element[i] = (byte) b; + out.write(element); + } + + /** + * Encodes a SASL OS to the current buffer. + * + * @param b the OS element. + * @throws SaslEncodingException if an encoding size constraint is violated. + * @throws IOException if any other I/O exception occurs during the operation. + */ + public void setOS(byte[] b) throws IOException + { + final int length = b.length; + if (length > Registry.SASL_ONE_BYTE_MAX_LIMIT) + throw new SaslEncodingException("SASL octet-sequence too long"); + out.write(length & 0xFF); + out.write(b); + } + + /** + * Encodes a SASL EOS to the current buffer. + * + * @param b the EOS element. + * @throws SaslEncodingException if an encoding size constraint is violated. + * @throws IOException if any other I/O exception occurs during the operation. + */ + public void setEOS(byte[] b) throws IOException + { + final int length = b.length; + if (length > Registry.SASL_TWO_BYTE_MAX_LIMIT) + throw new SaslEncodingException("SASL extended octet-sequence too long"); + byte[] lengthBytes = { (byte)(length >>> 8), (byte) length }; + out.write(lengthBytes); + out.write(b); + } + + /** + * Encodes a SASL MPI to the current buffer. + * + * @param val the MPI element. + * @throws SaslEncodingException if an encoding size constraint is violated. + * @throws IOException if any other I/O exception occurs during the operation. + */ + public void setMPI(BigInteger val) throws IOException + { + byte[] b = Util.trim(val); + final int length = b.length; + if (length > Registry.SASL_TWO_BYTE_MAX_LIMIT) + throw new SaslEncodingException("SASL multi-precision integer too long"); + byte[] lengthBytes = { (byte)(length >>> 8), (byte) length }; + out.write(lengthBytes); + out.write(b); + } + + /** + * Encodes a SASL Text to the current buffer. + * + * @param str the Text element. + * @throws SaslEncodingException if an encoding size constraint is violated. + * @throws SaslEncodingException if the UTF-8 encoding is not supported on + * this platform. + * @throws IOException if any other I/O exception occurs during the operation. + */ + public void setText(String str) throws IOException + { + byte[] b = str.getBytes("UTF8"); + final int length = b.length; + if (length > Registry.SASL_TWO_BYTE_MAX_LIMIT) + throw new SaslEncodingException("SASL text too long"); + byte[] lengthBytes = { (byte)(length >>> 8), (byte) length }; + out.write(lengthBytes); + out.write(b); + } + + /** + * Returns the encoded form of the current buffer including the 4-byte length + * header. + * + * @throws SaslEncodingException if an encoding size constraint is violated. + */ + public byte[] encode() throws SaslEncodingException + { + byte[] buffer = wrap(); + final int length = buffer.length; + byte[] result = new byte[length + 4]; + result[0] = (byte)(length >>> 24); + result[1] = (byte)(length >>> 16); + result[2] = (byte)(length >>> 8); + result[3] = (byte) length; + System.arraycopy(buffer, 0, result, 4, length); + return result; + } + + /** + * Returns the encoded form of the current buffer excluding the 4-byte length + * header. + * + * @throws SaslEncodingException if an encoding size constraint is violated. + */ + public byte[] wrap() throws SaslEncodingException + { + final int length = out.size(); + if (length > Registry.SASL_BUFFER_MAX_LIMIT || length < 0) + throw new SaslEncodingException("SASL buffer too long"); + return out.toByteArray(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/SaslEncodingException.java b/libjava/classpath/gnu/javax/crypto/sasl/SaslEncodingException.java new file mode 100644 index 000000000..5836270ac --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/SaslEncodingException.java @@ -0,0 +1,66 @@ +/* SaslEncodingException.java -- + Copyright (C) 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.crypto.sasl; + +import javax.security.sasl.SaslException; + +/** + * A checked exception, thrown when an exception occurs while decoding a SASL + * buffer and/or a SASL data element from/to a buffer. + */ +public class SaslEncodingException + extends SaslException +{ + /** Constructs a SaslEncodingException with no detail message. */ + public SaslEncodingException() + { + super(); + } + + /** + * Constructs a SaslEncodingException with the specified detail + * message. + * + * @param s the detail message. + */ + public SaslEncodingException(String s) + { + super(s); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/SaslInputStream.java b/libjava/classpath/gnu/javax/crypto/sasl/SaslInputStream.java new file mode 100644 index 000000000..6a6c85751 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/SaslInputStream.java @@ -0,0 +1,393 @@ +/* SaslInputStream.java -- + Copyright (C) 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.crypto.sasl; + +import gnu.java.security.Configuration; +import gnu.java.security.util.Util; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InterruptedIOException; +import java.util.logging.Logger; + +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslServer; + +/** + * An input stream that uses either a {@link SaslClient} or a {@link SaslServer} + * to process the data through these entities' security layer filter(s). + */ +public class SaslInputStream + extends InputStream +{ + private static final Logger log = Logger.getLogger(SaslInputStream.class.getName()); + private SaslClient client; + private SaslServer server; + private int maxRawSendSize; + private InputStream source; + private byte[] internalBuf; + + public SaslInputStream(SaslClient client, InputStream source) + throws IOException + { + super(); + + this.client = client; + String size = (String) client.getNegotiatedProperty(Sasl.RAW_SEND_SIZE); + maxRawSendSize = Integer.parseInt(size); + server = null; + this.source = source; + } + + public SaslInputStream(SaslServer server, InputStream source) + throws IOException + { + super(); + + this.server = server; + String size = (String) server.getNegotiatedProperty(Sasl.RAW_SEND_SIZE); + maxRawSendSize = Integer.parseInt(size); + client = null; + this.source = source; + } + + public int available() throws IOException + { + return (internalBuf == null) ? 0 : internalBuf.length; + } + + public void close() throws IOException + { + source.close(); + } + + /** + * Reads the next byte of data from the input stream. The value byte is + * returned as an int in the range 0 to + * 255. If no byte is available because the end of the stream + * has been reached, the value -1 is returned. This method + * blocks until input data is available, the end of the stream is detected, or + * an exception is thrown. + *

+ * From a SASL mechanism provider's perspective, if a security layer has been + * negotiated, the underlying source is expected to contain SASL + * buffers, as defined in RFC 2222. Four octets in network byte order in the + * front of each buffer identify the length of the buffer. The provider is + * responsible for performing any integrity checking or other processing on + * the buffer before returning the data as a stream of octets. For example, + * the protocol driver's request for a single octet from the stream might; + * i.e. an invocation of this method, may result in an entire SASL buffer + * being read and processed before that single octet can be returned. + * + * @return the next byte of data, or -1 if the end of the + * stream is reached. + * @throws IOException if an I/O error occurs. + */ + public int read() throws IOException + { + int result = -1; + if (internalBuf != null && internalBuf.length > 0) + { + result = internalBuf[0] & 0xFF; + if (internalBuf.length == 1) + internalBuf = new byte[0]; + else + { + byte[] tmp = new byte[internalBuf.length - 1]; + System.arraycopy(internalBuf, 1, tmp, 0, tmp.length); + internalBuf = tmp; + } + } + else + { + byte[] buf = new byte[1]; + int check = read(buf); + result = (check > 0) ? (buf[0] & 0xFF) : -1; + } + return result; + } + + /** + * Reads up to len bytes of data from the underlying source + * input stream into an array of bytes. An attempt is made to read as many as + * len bytes, but a smaller number may be read, possibly zero. + * The number of bytes actually read is returned as an integer. + *

+ * This method blocks until input data is available, end of file is detected, + * or an exception is thrown. + *

+ * If b is null, a {@link NullPointerException} + * is thrown. + *

+ * If off is negative, or len is negative, or + * off+len is greater than the length of the array + * b, then an {@link IndexOutOfBoundsException} is thrown. + *

+ * If len is zero, then no bytes are read and 0 + * is returned; otherwise, there is an attempt to read at least one byte. If + * no byte is available because the stream is at end of file, the value + * -1 is returned; otherwise, at least one byte is read and + * stored into b. + *

+ * The first byte read is stored into element b[off], the next + * one into b[off+1], and so on. The number of bytes read is, + * at most, equal to len. Let k be the number + * of bytes actually read; these bytes will be stored in elements + * b[off] through b[off+k-1], leaving elements + * b[off+k] through b[off+len-1] unaffected. + *

+ * In every case, elements b[0] through b[off] + * and elements b[off+len] through b[b.length-1] + * are unaffected. + *

+ * If the first byte cannot be read for any reason other than end of file, + * then an {@link IOException} is thrown. In particular, an + * {@link IOException} is thrown if the input stream has been closed. + *

+ * From the SASL mechanism provider's perspective, if a security layer has + * been negotiated, the underlying source is expected to contain SASL + * buffers, as defined in RFC 2222. Four octets in network byte order in the + * front of each buffer identify the length of the buffer. The provider is + * responsible for performing any integrity checking or other processing on + * the buffer before returning the data as a stream of octets. The protocol + * driver's request for a single octet from the stream might result in an + * entire SASL buffer being read and processed before that single octet can be + * returned. + * + * @param b the buffer into which the data is read. + * @param off the start offset in array b at which the data is + * wricodeen. + * @param len the maximum number of bytes to read. + * @return the total number of bytes read into the buffer, or -1 + * if there is no more data because the end of the stream has been + * reached. + * @throws IOException if an I/O error occurs. + */ + public int read(byte[] b, int off, int len) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "read", new Object[] { + b, Integer.valueOf(off), Integer.valueOf(len) + }); + if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) + || ((off + len) < 0)) + throw new IndexOutOfBoundsException("off=" + off + ", len=" + len + + ", b.length=" + b.length); + if (len == 0) + { + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "read", Integer.valueOf(0)); + return 0; + } + if (Configuration.DEBUG) + log.finer("Available: " + available()); + int result = 0; + if (internalBuf == null || internalBuf.length < 1) + try + { + internalBuf = readSaslBuffer(); + if (internalBuf == null) + { + if (Configuration.DEBUG) + { + log.finer("Underlying stream empty. Returning -1"); + log.exiting(this.getClass().getName(), "read", + Integer.valueOf(-1)); + } + return -1; + } + } + catch (InterruptedIOException x) + { + if (Configuration.DEBUG) + { + log.finer("Reading thread was interrupted. Returning -1"); + log.throwing(this.getClass().getName(), "read", x); + log.exiting(this.getClass().getName(), "read", + Integer.valueOf(-1)); + } + return -1; + } + if (len <= internalBuf.length) + { + result = len; + System.arraycopy(internalBuf, 0, b, off, len); + if (len == internalBuf.length) + internalBuf = null; + else + { + byte[] tmp = new byte[internalBuf.length - len]; + System.arraycopy(internalBuf, len, tmp, 0, tmp.length); + internalBuf = tmp; + } + } + else + { + // first copy the available bytes to b + result = internalBuf.length; + System.arraycopy(internalBuf, 0, b, off, result); + internalBuf = null; + off += result; + len -= result; + int remaining; // count of bytes remaining in buffer after an iteration + int delta; // count of bytes moved to b after an iteration + int datalen; + byte[] data; + while (len > 0) + // we need to read SASL buffers, as long as there are at least + // 4 bytes available at the source + if (source.available() > 3) + { + // process a buffer + data = readSaslBuffer(); + if (data == null) + { + if (Configuration.DEBUG) + log.finer("Underlying stream exhausted. Breaking..."); + break; + } + datalen = data.length; + // copy [part of] the result to b + remaining = (datalen <= len) ? 0 : datalen - len; + delta = datalen - remaining; + System.arraycopy(data, 0, b, off, delta); + if (remaining > 0) + { + internalBuf = new byte[remaining]; + System.arraycopy(data, delta, internalBuf, 0, remaining); + } + // update off, result and len + off += delta; + result += delta; + len -= delta; + } + else + { // nothing much we can do except return what we have + if (Configuration.DEBUG) + log.finer("Not enough bytes in source to read a buffer. Breaking..."); + break; + } + } + if (Configuration.DEBUG) + { + log.finer("Remaining: " + + (internalBuf == null ? 0 : internalBuf.length)); + log.exiting(this.getClass().getName(), "read()", String.valueOf(result)); + } + return result; + } + + /** + * Reads a SASL buffer from the underlying source if at least 4 bytes are + * available. + * + * @return the byte[] of decoded buffer contents, or null if the underlying + * source was exhausted. + * @throws IOException if an I/O exception occurs during the operation. + */ + private byte[] readSaslBuffer() throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "readSaslBuffer()"); + int realLength; // check if we read as many bytes as we're supposed to + byte[] result = new byte[4]; + try + { + realLength = source.read(result); + if (realLength == -1) + { + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "readSaslBuffer"); + return null; + } + } + catch (IOException x) + { + if (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "readSaslBuffer", x); + throw x; + } + if (realLength != 4) + throw new IOException("Was expecting 4 but found " + realLength); + int bufferLength = result[0] << 24 + | (result[1] & 0xFF) << 16 + | (result[2] & 0xFF) << 8 + | (result[3] & 0xFF); + if (Configuration.DEBUG) + log.finer("SASL buffer size: " + bufferLength); + if (bufferLength > maxRawSendSize || bufferLength < 0) + throw new SaslEncodingException("SASL buffer (security layer) too long"); + + result = new byte[bufferLength]; + try + { + realLength = source.read(result); + } + catch (IOException x) + { + if (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "readSaslBuffer", x); + throw x; + } + if (realLength != bufferLength) + throw new IOException("Was expecting " + bufferLength + " but found " + + realLength); + if (Configuration.DEBUG) + { + log.finer("Incoming buffer (before security) (hex): " + + Util.dumpString(result)); + log.finer("Incoming buffer (before security) (str): \"" + + new String(result) + "\""); + } + if (client != null) + result = client.unwrap(result, 0, realLength); + else + result = server.unwrap(result, 0, realLength); + if (Configuration.DEBUG) + { + log.finer("Incoming buffer (after security) (hex): " + + Util.dumpString(result)); + log.finer("Incoming buffer (after security) (str): \"" + + new String(result) + "\""); + log.exiting(this.getClass().getName(), "readSaslBuffer"); + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/SaslOutputStream.java b/libjava/classpath/gnu/javax/crypto/sasl/SaslOutputStream.java new file mode 100644 index 000000000..0de1ce850 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/SaslOutputStream.java @@ -0,0 +1,175 @@ +/* SaslOutputStream.java -- + Copyright (C) 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.crypto.sasl; + +import gnu.java.security.Configuration; +import gnu.java.security.util.Util; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.logging.Logger; + +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslServer; + +/** + * An output stream that uses either a {@link SaslClient} or a {@link SaslServer} + * to process the data through these entities' security layer filter(s). + */ +public class SaslOutputStream + extends OutputStream +{ + private static final Logger log = Logger.getLogger(SaslOutputStream.class.getName()); + private SaslClient client; + private SaslServer server; + private int maxRawSendSize; + private OutputStream dest; + + public SaslOutputStream(SaslClient client, OutputStream dest) + throws IOException + { + super(); + + this.client = client; + String size = (String) client.getNegotiatedProperty(Sasl.RAW_SEND_SIZE); + maxRawSendSize = Integer.parseInt(size); + server = null; + this.dest = dest; + } + + public SaslOutputStream(SaslServer server, OutputStream dest) + throws IOException + { + super(); + + this.server = server; + String size = (String) server.getNegotiatedProperty(Sasl.RAW_SEND_SIZE); + maxRawSendSize = Integer.parseInt(size); + client = null; + this.dest = dest; + } + + public void close() throws IOException + { + dest.flush(); + dest.close(); + } + + public void flush() throws IOException + { + dest.flush(); + } + + /** + * When writing octets to the resulting stream, if a security layer has been + * negotiated, each piece of data written (by a single invocation of + * write()) will be encapsulated as a SASL buffer, as defined in + * RFC 2222, and then written to the underlying dest output stream. + */ + public void write(int b) throws IOException + { + write(new byte[] { (byte) b }); + } + + /** + * When writing octets to the resulting stream, if a security layer has been + * negotiated, each piece of data written (by a single invocation of + * write()) will be encapsulated as a SASL buffer, as defined in + * RFC 2222, and then written to the underlying dest output stream. + */ + public void write(byte[] b, int off, int len) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "write"); + if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) + || ((off + len) < 0)) + throw new IndexOutOfBoundsException("off=" + off + ", len=" + len + + ", b.length=" + b.length); + if (len == 0) + { + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "write"); + return; + } + int chunckSize, length, chunck = 1; + byte[] output = null, result; + if (Configuration.DEBUG) + log.finer("About to wrap " + len + " byte(s)..."); + while (len > 0) + { + chunckSize = (len > maxRawSendSize ? maxRawSendSize : len); + if (Configuration.DEBUG) + { + log.finer("Outgoing buffer (before security) (hex): " + + Util.dumpString(b, off, chunckSize)); + log.finer("Outgoing buffer (before security) (str): \"" + + new String(b, off, chunckSize) + "\""); + } + if (client != null) + output = client.wrap(b, off, chunckSize); + else + output = server.wrap(b, off, chunckSize); + + if (Configuration.DEBUG) + { + log.finer("Outgoing buffer (after security) (hex): " + + Util.dumpString(output)); + log.finer("Outgoing buffer (after security) (str): \"" + + new String(output) + "\""); + } + length = output.length; + result = new byte[length + 4]; + result[0] = (byte)(length >>> 24); + result[1] = (byte)(length >>> 16); + result[2] = (byte)(length >>> 8); + result[3] = (byte) length; + System.arraycopy(output, 0, result, 4, length); + dest.write(result); + off += chunckSize; + len -= chunckSize; + if (Configuration.DEBUG) + log.finer("Wrapped chunck #" + chunck); + chunck++; + } + dest.flush(); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "write"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/SaslUtil.java b/libjava/classpath/gnu/javax/crypto/sasl/SaslUtil.java new file mode 100644 index 000000000..b17d9536e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/SaslUtil.java @@ -0,0 +1,75 @@ +/* SaslUtil.java -- + Copyright (C) 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.crypto.sasl; + +import gnu.java.security.util.Util; + +import java.security.MessageDigest; + +/** + * Utility methods for SASL-related classes. + */ +public class SaslUtil +{ + private SaslUtil() + { + super(); + } + + public static final boolean validEmailAddress(String address) + { + // need to do better than this + return (address.indexOf("@") != -1); + } + + /** Returns the context of the designated hash as a string. */ + public static final String dump(MessageDigest md) + { + String result; + try + { + result = Util.dumpString(((MessageDigest) md.clone()).digest()); + } + catch (Exception ignored) + { + result = "..."; + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/ServerFactory.java b/libjava/classpath/gnu/javax/crypto/sasl/ServerFactory.java new file mode 100644 index 000000000..6df44c08c --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/ServerFactory.java @@ -0,0 +1,158 @@ +/* ServerFactory.java -- + Copyright (C) 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.crypto.sasl; + +import gnu.java.security.Registry; +import gnu.javax.crypto.sasl.anonymous.AnonymousServer; +import gnu.javax.crypto.sasl.crammd5.CramMD5Server; +import gnu.javax.crypto.sasl.plain.PlainServer; +import gnu.javax.crypto.sasl.srp.SRPServer; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslServerFactory; + +/** + * The implementation of the {@link SaslServerFactory}. + */ +public class ServerFactory + implements SaslServerFactory +{ + // implicit 0-arguments constructor + + public static final Set getNames() + { + return Collections.unmodifiableSet(new HashSet(Arrays.asList(getNamesInternal(null)))); + } + + private static final String[] getNamesInternal(Map props) + { + String[] all = new String[] { + Registry.SASL_SRP_MECHANISM, + Registry.SASL_CRAM_MD5_MECHANISM, + Registry.SASL_PLAIN_MECHANISM, + Registry.SASL_ANONYMOUS_MECHANISM }; + List result = new ArrayList(4); + int i; + for (i = 0; i < all.length;) + result.add(all[i++]); + if (props == null) + return (String[]) result.toArray(new String[0]); // all + if (hasPolicy(Sasl.POLICY_PASS_CREDENTIALS, props)) // none + return new String[0]; + if (hasPolicy(Sasl.POLICY_NOPLAINTEXT, props)) + result.remove(Registry.SASL_PLAIN_MECHANISM); + if (hasPolicy(Sasl.POLICY_NOACTIVE, props)) + { + result.remove(Registry.SASL_CRAM_MD5_MECHANISM); + result.remove(Registry.SASL_PLAIN_MECHANISM); + } + if (hasPolicy(Sasl.POLICY_NODICTIONARY, props)) + { + result.remove(Registry.SASL_CRAM_MD5_MECHANISM); + result.remove(Registry.SASL_PLAIN_MECHANISM); + } + if (hasPolicy(Sasl.POLICY_NOANONYMOUS, props)) + { + result.remove(Registry.SASL_ANONYMOUS_MECHANISM); + } + if (hasPolicy(Sasl.POLICY_FORWARD_SECRECY, props)) + { + result.remove(Registry.SASL_CRAM_MD5_MECHANISM); + result.remove(Registry.SASL_ANONYMOUS_MECHANISM); + result.remove(Registry.SASL_PLAIN_MECHANISM); + } + return (String[]) result.toArray(new String[0]); + } + + public static final ServerMechanism getInstance(String mechanism) + { + if (mechanism == null) + return null; + mechanism = mechanism.trim().toUpperCase(); + if (mechanism.equals(Registry.SASL_SRP_MECHANISM)) + return new SRPServer(); + if (mechanism.equals(Registry.SASL_CRAM_MD5_MECHANISM)) + return new CramMD5Server(); + if (mechanism.equals(Registry.SASL_PLAIN_MECHANISM)) + return new PlainServer(); + if (mechanism.equals(Registry.SASL_ANONYMOUS_MECHANISM)) + return new AnonymousServer(); + return null; + } + + public SaslServer createSaslServer(String mechanism, String protocol, + String serverName, Map props, + CallbackHandler cbh) throws SaslException + { + ServerMechanism result = getInstance(mechanism); + if (result != null) + { + HashMap attributes = new HashMap(); + if (props != null) + attributes.putAll(props); + attributes.put(Registry.SASL_PROTOCOL, protocol); + attributes.put(Registry.SASL_SERVER_NAME, serverName); + attributes.put(Registry.SASL_CALLBACK_HANDLER, cbh); + result.init(attributes); + } + return result; + } + + public String[] getMechanismNames(Map props) + { + return getNamesInternal(props); + } + + private static boolean hasPolicy(String propertyName, Map props) + { + return "true".equalsIgnoreCase(String.valueOf(props.get(propertyName))); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/ServerMechanism.java b/libjava/classpath/gnu/javax/crypto/sasl/ServerMechanism.java new file mode 100644 index 000000000..71dfdd4e0 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/ServerMechanism.java @@ -0,0 +1,294 @@ +/* ServerMechanism.java -- + Copyright (C) 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.crypto.sasl; + +import gnu.java.security.Registry; + +import java.util.HashMap; +import java.util.Map; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +/** + * A base class to facilitate implementing SASL server-side mechanisms. + */ +public abstract class ServerMechanism + implements SaslServer +{ + /** Name of this mechanism. */ + protected String mechanism; + /** Name of protocol using this mechanism. */ + protected String protocol; + /** Name of server to authenticate to. */ + protected String serverName; + /** Properties of qualities desired for this mechanism. */ + protected Map properties; + /** Callback handler to use with this mechanism instance. */ + protected CallbackHandler handler; + /** Whether authentication phase is completed (true) or not (false). */ + protected boolean complete = false; + /** The authorisation identity. */ + protected String authorizationID; + /** Channel binding data to use with this mechanism instance. */ + protected byte[] channelBinding; + /** The state of the authentication automaton. -1 means uninitialised. */ + protected int state = -1; + /** The provider for authentication information. */ + protected IAuthInfoProvider authenticator; + + protected ServerMechanism(final String mechanism) + { + super(); + + this.mechanism = mechanism; + this.authenticator = AuthInfo.getProvider(mechanism); + this.state = -1; + } + + protected abstract void initMechanism() throws SaslException; + + protected abstract void resetMechanism() throws SaslException; + + public abstract byte[] evaluateResponse(byte[] response) throws SaslException; + + public boolean isComplete() + { + return complete; + } + + public byte[] unwrap(final byte[] incoming, final int offset, final int len) + throws SaslException + { + if (! isComplete()) + throw new IllegalMechanismStateException(); + return this.engineUnwrap(incoming, offset, len); + } + + public byte[] wrap(final byte[] outgoing, final int offset, final int len) + throws SaslException + { + if (! isComplete()) + throw new IllegalMechanismStateException(); + return this.engineWrap(outgoing, offset, len); + } + + public String getMechanismName() + { + return this.mechanism; + } + + public String getAuthorizationID() + { + return this.authorizationID; + } + + public Object getNegotiatedProperty(final String propName) + { + if (! isComplete()) + throw new IllegalStateException(); + if (Sasl.QOP.equals(propName)) + return getNegotiatedQOP(); + if (Sasl.STRENGTH.equals(propName)) + return getNegotiatedStrength(); + if (Sasl.SERVER_AUTH.equals(propName)) + return getNegotiatedServerAuth(); + if (Sasl.MAX_BUFFER.equals(propName)) + return getNegotiatedMaxBuffer(); + if (Sasl.RAW_SEND_SIZE.equals(propName)) + return getNegotiatedRawSendSize(); + if (Sasl.POLICY_NOPLAINTEXT.equals(propName)) + return getNegotiatedPolicyNoPlainText(); + if (Sasl.POLICY_NOACTIVE.equals(propName)) + return getNegotiatedPolicyNoActive(); + if (Sasl.POLICY_NODICTIONARY.equals(propName)) + return getNegotiatedPolicyNoDictionary(); + if (Sasl.POLICY_NOANONYMOUS.equals(propName)) + return getNegotiatedPolicyNoAnonymous(); + if (Sasl.POLICY_FORWARD_SECRECY.equals(propName)) + return getNegotiatedPolicyForwardSecrecy(); + if (Sasl.POLICY_PASS_CREDENTIALS.equals(propName)) + return getNegotiatedPolicyPassCredentials(); + if (Sasl.REUSE.equals(propName)) + return getReuse(); + return null; + } + + public void dispose() throws SaslException + { + reset(); + } + + protected String getNegotiatedQOP() + { + return Registry.QOP_AUTH; + } + + protected String getNegotiatedStrength() + { + return Registry.STRENGTH_LOW; + } + + protected String getNegotiatedServerAuth() + { + return Registry.SERVER_AUTH_FALSE; + } + + protected String getNegotiatedMaxBuffer() + { + return null; + } + + protected String getNegotiatedPolicyNoPlainText() + { + return null; + } + + protected String getNegotiatedPolicyNoActive() + { + return null; + } + + protected String getNegotiatedPolicyNoDictionary() + { + return null; + } + + protected String getNegotiatedPolicyNoAnonymous() + { + return null; + } + + protected String getNegotiatedPolicyForwardSecrecy() + { + return null; + } + + protected String getNegotiatedPolicyPassCredentials() + { + return null; + } + + protected String getNegotiatedRawSendSize() + { + return String.valueOf(Registry.SASL_BUFFER_MAX_LIMIT); + } + + protected String getReuse() + { + return Registry.REUSE_FALSE; + } + + protected byte[] engineUnwrap(final byte[] incoming, final int offset, + final int len) throws SaslException + { + final byte[] result = new byte[len]; + System.arraycopy(incoming, offset, result, 0, len); + return result; + } + + protected byte[] engineWrap(final byte[] outgoing, final int offset, + final int len) throws SaslException + { + final byte[] result = new byte[len]; + System.arraycopy(outgoing, offset, result, 0, len); + return result; + } + + /** + * Initialises the mechanism with designated attributes. Permissible names and + * values are mechanism specific. + * + * @param attributes a set of name-value pairs that describes the desired + * future behaviour of this instance. + * @throws IllegalMechanismStateException if the instance is already + * initialised. + * @throws SaslException if an exception occurs during the process. + */ + public void init(final Map attributes) throws SaslException + { + if (state != -1) + throw new IllegalMechanismStateException("init()"); + if (properties == null) + properties = new HashMap(); + else + properties.clear(); + if (attributes != null) + { + protocol = (String) attributes.get(Registry.SASL_PROTOCOL); + serverName = (String) attributes.get(Registry.SASL_SERVER_NAME); + handler = (CallbackHandler) attributes.get(Registry.SASL_CALLBACK_HANDLER); + channelBinding = (byte[]) attributes.get(Registry.SASL_CHANNEL_BINDING); + properties.putAll(attributes); + } + else + handler = null; + if (protocol == null) + protocol = ""; + if (serverName == null) + serverName = ""; + if (authenticator != null) + authenticator.activate(properties); + if (channelBinding == null) + channelBinding = new byte[0]; + initMechanism(); + complete = false; + state = 0; + } + + /** + * Resets the mechanism instance for re-initialisation and use with other + * characteristics. + * + * @throws SaslException if an exception occurs during the process. + */ + public void reset() throws SaslException + { + resetMechanism(); + properties.clear(); + if (authenticator != null) + authenticator.passivate(); + protocol = serverName = null; + channelBinding = null; + complete = false; + state = -1; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/UserAlreadyExistsException.java b/libjava/classpath/gnu/javax/crypto/sasl/UserAlreadyExistsException.java new file mode 100644 index 000000000..615fabb57 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/UserAlreadyExistsException.java @@ -0,0 +1,70 @@ +/* UserAlreadyExistsException.java -- + Copyright (C) 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.crypto.sasl; + +import javax.security.sasl.SaslException; + +/** + * A checked exception thrown to indicate that a designated user is already + * known to the the authentication layer. + */ +public class UserAlreadyExistsException + extends SaslException +{ + /** + * Constructs a UserAlreadyExistsException with no detail + * message. + */ + public UserAlreadyExistsException() + { + super(); + } + + /** + * Constructs a UserAlreadyExistsException with the specified + * detail message. In the case of this exception, the detail message + * designates the offending username. + * + * @param userName the detail message, which in this case is the username. + */ + public UserAlreadyExistsException(String userName) + { + super(userName); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousClient.java b/libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousClient.java new file mode 100644 index 000000000..860efb4f9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousClient.java @@ -0,0 +1,102 @@ +/* AnonymousClient.java -- + Copyright (C) 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.crypto.sasl.anonymous; + +import gnu.java.security.Registry; +import gnu.javax.crypto.sasl.ClientMechanism; +import gnu.javax.crypto.sasl.IllegalMechanismStateException; + +import java.io.UnsupportedEncodingException; + +import javax.security.sasl.AuthenticationException; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslException; + +/** + * The ANONYMOUS client-side mechanism. + */ +public class AnonymousClient + extends ClientMechanism + implements SaslClient +{ + public AnonymousClient() + { + super(Registry.SASL_ANONYMOUS_MECHANISM); + } + + protected void initMechanism() throws SaslException + { + } + + protected void resetMechanism() throws SaslException + { + } + + public boolean hasInitialResponse() + { + return true; + } + + public byte[] evaluateChallenge(final byte[] challenge) throws SaslException + { + if (complete) + { + throw new IllegalMechanismStateException("evaluateChallenge()"); + } + return response(); + } + + private byte[] response() throws SaslException + { + if (! AnonymousUtil.isValidTraceInformation(authorizationID)) + throw new AuthenticationException( + "Authorisation ID is not a valid email address"); + complete = true; + final byte[] result; + try + { + result = authorizationID.getBytes("UTF-8"); + } + catch (UnsupportedEncodingException x) + { + throw new AuthenticationException("response()", x); + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousServer.java b/libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousServer.java new file mode 100644 index 000000000..675194caa --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousServer.java @@ -0,0 +1,90 @@ +/* AnonymousServer.java -- + Copyright (C) 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.crypto.sasl.anonymous; + +import gnu.java.security.Registry; +import gnu.javax.crypto.sasl.ServerMechanism; + +import java.io.UnsupportedEncodingException; + +import javax.security.sasl.AuthenticationException; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +/** + * The ANONYMOUS server-side mechanism. + */ +public class AnonymousServer + extends ServerMechanism + implements SaslServer +{ + public AnonymousServer() + { + super(Registry.SASL_ANONYMOUS_MECHANISM); + } + + protected void initMechanism() throws SaslException + { + } + + protected void resetMechanism() throws SaslException + { + } + + public byte[] evaluateResponse(final byte[] response) throws SaslException + { + if (response == null) + return null; + try + { + authorizationID = new String(response, "UTF-8"); + } + catch (UnsupportedEncodingException x) + { + throw new AuthenticationException("evaluateResponse()", x); + } + if (AnonymousUtil.isValidTraceInformation(authorizationID)) + { + this.complete = true; + return null; + } + authorizationID = null; + throw new AuthenticationException("Invalid email address"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousUtil.java b/libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousUtil.java new file mode 100644 index 000000000..bb59779d6 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousUtil.java @@ -0,0 +1,83 @@ +/* AnonymousUtil.java -- + Copyright (C) 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.crypto.sasl.anonymous; + +import gnu.javax.crypto.sasl.SaslUtil; + +/** + * An ANONYMOUS-specific utility class. + */ +public class AnonymousUtil +{ + /** Trivial private constructor to enforce Singleton pattern. */ + private AnonymousUtil() + { + super(); + } + + static boolean isValidTraceInformation(String traceInformation) + { + if (traceInformation == null) + return false; + if (traceInformation.length() == 0) + return true; + if (SaslUtil.validEmailAddress(traceInformation)) + return true; + return isValidToken(traceInformation); + } + + static boolean isValidToken(String token) + { + if (token == null) + return false; + if (token.length() == 0) + return false; + if (token.length() > 255) + return false; + if (token.indexOf('@') != -1) + return false; + for (int i = 0; i < token.length(); i++) + { + char c = token.charAt(i); + if (c < 0x20 || c > 0x7E) + return false; + } + return true; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5AuthInfoProvider.java b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5AuthInfoProvider.java new file mode 100644 index 000000000..e3d8b8f08 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5AuthInfoProvider.java @@ -0,0 +1,166 @@ +/* CramMD5AuthInfoProvider.java -- + Copyright (C) 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.crypto.sasl.crammd5; + +import gnu.java.security.Registry; +import gnu.javax.crypto.sasl.IAuthInfoProvider; +import gnu.javax.crypto.sasl.NoSuchUserException; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import javax.security.sasl.AuthenticationException; + +/** + * The CRAM-MD5 mechanism authentication information provider implementation. + */ +public class CramMD5AuthInfoProvider + implements IAuthInfoProvider +{ + private PasswordFile passwordFile = null; + + // implicit 0-args constrcutor + + public void activate(Map context) throws AuthenticationException + { + try + { + if (context == null) + passwordFile = new PasswordFile(); + else + { + String pfn = (String) context.get(CramMD5Registry.PASSWORD_FILE); + if (pfn == null) + passwordFile = new PasswordFile(); + else + passwordFile = new PasswordFile(pfn); + } + } + catch (IOException x) + { + throw new AuthenticationException("activate()", x); + } + } + + public void passivate() throws AuthenticationException + { + passwordFile = null; + } + + public boolean contains(String userName) throws AuthenticationException + { + if (passwordFile == null) + throw new AuthenticationException("contains()", + new IllegalStateException()); + boolean result = false; + try + { + result = passwordFile.contains(userName); + } + catch (IOException x) + { + throw new AuthenticationException("contains()", x); + } + return result; + } + + public Map lookup(Map userID) throws AuthenticationException + { + if (passwordFile == null) + throw new AuthenticationException("lookup()", new IllegalStateException()); + Map result = new HashMap(); + try + { + String userName = (String) userID.get(Registry.SASL_USERNAME); + if (userName == null) + throw new NoSuchUserException(""); + String[] data = passwordFile.lookup(userName); + result.put(Registry.SASL_USERNAME, data[0]); + result.put(Registry.SASL_PASSWORD, data[1]); + result.put(CramMD5Registry.UID_FIELD, data[2]); + result.put(CramMD5Registry.GID_FIELD, data[3]); + result.put(CramMD5Registry.GECOS_FIELD, data[4]); + result.put(CramMD5Registry.DIR_FIELD, data[5]); + result.put(CramMD5Registry.SHELL_FIELD, data[6]); + } + catch (Exception x) + { + if (x instanceof AuthenticationException) + throw (AuthenticationException) x; + throw new AuthenticationException("lookup()", x); + } + return result; + } + + public void update(Map userCredentials) throws AuthenticationException + { + if (passwordFile == null) + throw new AuthenticationException("update()", new IllegalStateException()); + try + { + String userName = (String) userCredentials.get(Registry.SASL_USERNAME); + String password = (String) userCredentials.get(Registry.SASL_PASSWORD); + String uid = (String) userCredentials.get(CramMD5Registry.UID_FIELD); + String gid = (String) userCredentials.get(CramMD5Registry.GID_FIELD); + String gecos = (String) userCredentials.get(CramMD5Registry.GECOS_FIELD); + String dir = (String) userCredentials.get(CramMD5Registry.DIR_FIELD); + String shell = (String) userCredentials.get(CramMD5Registry.SHELL_FIELD); + if (uid == null || gid == null || gecos == null || dir == null + || shell == null) + passwordFile.changePasswd(userName, password); + else + { + String[] attributes = new String[] { uid, gid, gecos, dir, shell }; + passwordFile.add(userName, password, attributes); + } + } + catch (Exception x) + { + if (x instanceof AuthenticationException) + throw (AuthenticationException) x; + throw new AuthenticationException("update()", x); + } + } + + public Map getConfiguration(String mode) throws AuthenticationException + { + throw new AuthenticationException("", new UnsupportedOperationException()); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Client.java b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Client.java new file mode 100644 index 000000000..44f694e5c --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Client.java @@ -0,0 +1,168 @@ +/* CramMD5Client.java -- + Copyright (C) 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.crypto.sasl.crammd5; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; +import gnu.javax.crypto.sasl.ClientMechanism; + +import java.io.IOException; +import java.security.InvalidKeyException; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.sasl.AuthenticationException; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslException; + +/** + * The CRAM-MD5 SASL client-side mechanism. + */ +public class CramMD5Client + extends ClientMechanism + implements SaslClient +{ + public CramMD5Client() + { + super(Registry.SASL_CRAM_MD5_MECHANISM); + } + + protected void initMechanism() throws SaslException + { + } + + protected void resetMechanism() throws SaslException + { + } + + public boolean hasInitialResponse() + { + return false; + } + + public byte[] evaluateChallenge(final byte[] challenge) throws SaslException + { + if (challenge == null) + throw new SaslException("null challenge"); + try + { + final String username; + final char[] password; + Callback[] callbacks; + if ((! properties.containsKey(Registry.SASL_USERNAME)) + && (! properties.containsKey(Registry.SASL_PASSWORD))) + { + callbacks = new Callback[2]; + final NameCallback nameCB; + final String defaultName = System.getProperty("user.name"); + if (defaultName == null) + nameCB = new NameCallback("username: "); + else + nameCB = new NameCallback("username: ", defaultName); + final PasswordCallback pwdCB = new PasswordCallback("password: ", + false); + callbacks[0] = nameCB; + callbacks[1] = pwdCB; + this.handler.handle(callbacks); + username = nameCB.getName(); + password = pwdCB.getPassword(); + } + else + { + if (properties.containsKey(Registry.SASL_USERNAME)) + username = (String) properties.get(Registry.SASL_USERNAME); + else + { + callbacks = new Callback[1]; + final NameCallback nameCB; + final String defaultName = System.getProperty("user.name"); + if (defaultName == null) + nameCB = new NameCallback("username: "); + else + nameCB = new NameCallback("username: ", defaultName); + callbacks[0] = nameCB; + this.handler.handle(callbacks); + username = nameCB.getName(); + } + + if (properties.containsKey(Registry.SASL_PASSWORD)) + password = ((String) properties.get(Registry.SASL_PASSWORD)).toCharArray(); + else + { + callbacks = new Callback[1]; + final PasswordCallback pwdCB = new PasswordCallback("password: ", + false); + callbacks[0] = pwdCB; + this.handler.handle(callbacks); + password = pwdCB.getPassword(); + } + } + if (password == null) + throw new SaslException("null password supplied"); + final byte[] digest; + try + { + digest = CramMD5Util.createHMac(password, challenge); + } + catch (InvalidKeyException x) + { + throw new AuthenticationException("evaluateChallenge()", x); + } + final String response = username + " " + + Util.toString(digest).toLowerCase(); + this.complete = true; + return response.getBytes("UTF-8"); + } + catch (UnsupportedCallbackException x) + { + throw new AuthenticationException("evaluateChallenge()", x); + } + catch (IOException x) + { + throw new AuthenticationException("evaluateChallenge()", x); + } + } + + protected String getNegotiatedQOP() + { + return Registry.QOP_AUTH; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Registry.java b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Registry.java new file mode 100644 index 000000000..560eb854e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Registry.java @@ -0,0 +1,60 @@ +/* CramMD5Registry.java -- + Copyright (C) 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.crypto.sasl.crammd5; + +/** + * A list of properties common to CRAM-MD5 classes. + */ +public interface CramMD5Registry +{ + /** Name of the password file (used by the server) property. */ + String PASSWORD_FILE = "gnu.crypto.sasl.crammd5.password.file"; + /** Default password file (used by the server) pathname. */ + String DEFAULT_PASSWORD_FILE = "/etc/passwd"; + /** Name of the UID field in the plain password file. */ + String UID_FIELD = "crammd5.uid"; + /** Name of the GID field in the plain password file. */ + String GID_FIELD = "crammd5.gid"; + /** Name of the GECOS field in the plain password file. */ + String GECOS_FIELD = "crammd5.gecos"; + /** Name of the DIR field in the plain password file. */ + String DIR_FIELD = "crammd5.dir"; + /** Name of the SHELL field in the plain password file. */ + String SHELL_FIELD = "crammd5.shell"; +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Server.java b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Server.java new file mode 100644 index 000000000..1522f6b35 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Server.java @@ -0,0 +1,158 @@ +/* CramMD5Server.java -- + Copyright (C) 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.crypto.sasl.crammd5; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; +import gnu.javax.crypto.sasl.NoSuchUserException; +import gnu.javax.crypto.sasl.ServerMechanism; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.InvalidKeyException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import javax.security.sasl.AuthenticationException; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +/** + * The CRAM-MD5 SASL server-side mechanism. + */ +public class CramMD5Server + extends ServerMechanism + implements SaslServer +{ + private byte[] msgID; + + public CramMD5Server() + { + super(Registry.SASL_CRAM_MD5_MECHANISM); + } + + protected void initMechanism() throws SaslException + { + } + + protected void resetMechanism() throws SaslException + { + } + + public byte[] evaluateResponse(final byte[] response) throws SaslException + { + if (state == 0) + { + msgID = CramMD5Util.createMsgID(); + state++; + return msgID; + } + final String responseStr = new String(response); + final int index = responseStr.lastIndexOf(" "); + final String username = responseStr.substring(0, index); + final byte[] responseDigest; + try + { + responseDigest = responseStr.substring(index + 1).getBytes("UTF-8"); + } + catch (UnsupportedEncodingException x) + { + throw new AuthenticationException("evaluateResponse()", x); + } + // Look up the password + final char[] password = lookupPassword(username); + // Compute the digest + byte[] digest; + try + { + digest = CramMD5Util.createHMac(password, msgID); + } + catch (InvalidKeyException x) + { + throw new AuthenticationException("evaluateResponse()", x); + } + try + { + digest = Util.toString(digest).toLowerCase().getBytes("UTF-8"); + } + catch (UnsupportedEncodingException x) + { + throw new AuthenticationException("evaluateResponse()", x); + } + // Compare the received and computed digests + if (! Arrays.equals(digest, responseDigest)) + throw new AuthenticationException("Digest mismatch"); + state++; + return null; + } + + public boolean isComplete() + { + return (state == 2); + } + + protected String getNegotiatedQOP() + { + return Registry.QOP_AUTH; + } + + private char[] lookupPassword(final String userName) throws SaslException + { + try + { + if (! authenticator.contains(userName)) + throw new NoSuchUserException(userName); + final Map userID = new HashMap(); + userID.put(Registry.SASL_USERNAME, userName); + final Map credentials = authenticator.lookup(userID); + final String password = (String) credentials.get(Registry.SASL_PASSWORD); + if (password == null) + throw new AuthenticationException("lookupPassword()", + new InternalError()); + return password.toCharArray(); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new AuthenticationException("lookupPassword()", x); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Util.java b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Util.java new file mode 100644 index 000000000..a85c4c721 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Util.java @@ -0,0 +1,122 @@ +/* CramMD5Util.java -- + Copyright (C) 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.crypto.sasl.crammd5; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; +import gnu.javax.crypto.mac.HMacFactory; +import gnu.javax.crypto.mac.IMac; + +import java.io.UnsupportedEncodingException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.security.InvalidKeyException; +import java.util.HashMap; + +import javax.security.sasl.SaslException; + +/** + * A package-private CRAM-MD5-specific utility class. + */ +class CramMD5Util +{ + private CramMD5Util() + { + super(); + } + + static byte[] createMsgID() throws SaslException + { + final String encoded; + try + { + encoded = Util.toBase64(Thread.currentThread().getName().getBytes("UTF-8")); + } + catch (UnsupportedEncodingException x) + { + throw new SaslException("createMsgID()", x); + } + String hostname = "localhost"; + try + { + hostname = InetAddress.getLocalHost().getHostAddress(); + } + catch (UnknownHostException ignored) + { + } + final byte[] result; + try + { + result = new CPStringBuilder("<") + .append(encoded.substring(0,encoded.length())) + .append(".").append(String.valueOf(System.currentTimeMillis())) + .append("@").append(hostname).append(">") + .toString() + .getBytes("UTF-8"); + } + catch (UnsupportedEncodingException x) + { + throw new SaslException("createMsgID()", x); + } + return result; + } + + static byte[] createHMac(final char[] passwd, final byte[] data) + throws InvalidKeyException, SaslException + { + final IMac mac = HMacFactory.getInstance(Registry.HMAC_NAME_PREFIX + + Registry.MD5_HASH); + final HashMap map = new HashMap(); + final byte[] km; + try + { + km = new String(passwd).getBytes("UTF-8"); + } + catch (UnsupportedEncodingException x) + { + throw new SaslException("createHMac()", x); + } + map.put(IMac.MAC_KEY_MATERIAL, km); + mac.init(map); + mac.update(data, 0, data.length); + return mac.digest(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/crammd5/PasswordFile.java b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/PasswordFile.java new file mode 100644 index 000000000..65da4afdd --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/PasswordFile.java @@ -0,0 +1,240 @@ +/* PasswordFile.java -- + Copyright (C) 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.crypto.sasl.crammd5; + +import gnu.java.lang.CPStringBuilder; + +import gnu.javax.crypto.sasl.NoSuchUserException; +import gnu.javax.crypto.sasl.UserAlreadyExistsException; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.StringTokenizer; + +/** + * The CRAM-MD5 password file representation. + */ +public class PasswordFile +{ + private static String DEFAULT_FILE; + static + { + DEFAULT_FILE = System.getProperty(CramMD5Registry.PASSWORD_FILE, + CramMD5Registry.DEFAULT_PASSWORD_FILE); + } + private HashMap entries; + private File passwdFile; + private long lastmod; + + public PasswordFile() throws IOException + { + this(DEFAULT_FILE); + } + + public PasswordFile(final File pwFile) throws IOException + { + this(pwFile.getAbsolutePath()); + } + + public PasswordFile(final String fileName) throws IOException + { + passwdFile = new File(fileName); + update(); + } + + public synchronized void add(final String user, final String passwd, + final String[] attributes) throws IOException + { + checkCurrent(); // check if the entry exists + if (entries.containsKey(user)) + throw new UserAlreadyExistsException(user); + if (attributes.length != 5) + throw new IllegalArgumentException("Wrong number of attributes"); + final String[] fields = new String[7]; // create the new entry + fields[0] = user; + fields[1] = passwd; + System.arraycopy(attributes, 0, fields, 2, 5); + entries.put(user, fields); + savePasswd(); + } + + public synchronized void changePasswd(final String user, final String passwd) + throws IOException + { + checkCurrent(); + if (! entries.containsKey(user)) + throw new NoSuchUserException(user); + final String[] fields = (String[]) entries.get(user); // get existing entry + fields[1] = passwd; // modify the password field + entries.remove(user); // delete the existing entry + entries.put(user, fields); // add the new entry + savePasswd(); + } + + public synchronized String[] lookup(final String user) throws IOException + { + checkCurrent(); + if (! entries.containsKey(user)) + throw new NoSuchUserException(user); + return (String[]) entries.get(user); + } + + public synchronized boolean contains(final String s) throws IOException + { + checkCurrent(); + return entries.containsKey(s); + } + + private synchronized void update() throws IOException + { + lastmod = passwdFile.lastModified(); + readPasswd(new FileInputStream(passwdFile)); + } + + private void checkCurrent() throws IOException + { + if (passwdFile.lastModified() > lastmod) + update(); + } + + private synchronized void readPasswd(final InputStream in) throws IOException + { + final BufferedReader din = new BufferedReader(new InputStreamReader(in)); + String line; + entries = new HashMap(); + while ((line = din.readLine()) != null) + { + final String[] fields = new String[7]; + final StringTokenizer st = new StringTokenizer(line, ":", true); + try + { + fields[0] = st.nextToken(); // username + st.nextToken(); + fields[1] = st.nextToken(); // passwd + if (fields[1].equals(":")) + fields[1] = ""; + else + st.nextToken(); + fields[2] = st.nextToken(); // uid + if (fields[2].equals(":")) + fields[2] = ""; + else + st.nextToken(); + fields[3] = st.nextToken(); // gid + if (fields[3].equals(":")) + fields[3] = ""; + else + st.nextToken(); + fields[4] = st.nextToken(); // gecos + if (fields[4].equals(":")) + fields[4] = ""; + else + st.nextToken(); + fields[5] = st.nextToken(); // dir + if (fields[5].equals(":")) + fields[5] = ""; + else + st.nextToken(); + fields[6] = st.nextToken(); // shell + if (fields[6].equals(":")) + fields[6] = ""; + } + catch (NoSuchElementException x) + { + continue; + } + entries.put(fields[0], fields); + } + } + + private synchronized void savePasswd() throws IOException + { + if (passwdFile != null) + { + final FileOutputStream fos = new FileOutputStream(passwdFile); + PrintWriter pw = null; + try + { + pw = new PrintWriter(fos); + String key; + String[] fields; + CPStringBuilder sb; + int i; + for (Iterator it = entries.keySet().iterator(); it.hasNext();) + { + key = (String) it.next(); + fields = (String[]) entries.get(key); + sb = new CPStringBuilder(fields[0]); + for (i = 1; i < fields.length; i++) + sb.append(":").append(fields[i]); + pw.println(sb.toString()); + } + } + finally + { + if (pw != null) + try + { + pw.flush(); + } + finally + { + pw.close(); + } + try + { + fos.close(); + } + catch (IOException ignored) + { + } + lastmod = passwdFile.lastModified(); + } + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/plain/PasswordFile.java b/libjava/classpath/gnu/javax/crypto/sasl/plain/PasswordFile.java new file mode 100644 index 000000000..51542d2b2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/plain/PasswordFile.java @@ -0,0 +1,245 @@ +/* PasswordFile.java -- + Copyright (C) 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.crypto.sasl.plain; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.action.GetPropertyAction; +import gnu.javax.crypto.sasl.NoSuchUserException; +import gnu.javax.crypto.sasl.UserAlreadyExistsException; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.security.AccessController; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.NoSuchElementException; +import java.util.StringTokenizer; + +/** + * A representation of a Plain password file. + */ +public class PasswordFile +{ + private static String DEFAULT_FILE; + static + { + DEFAULT_FILE = (String) AccessController.doPrivileged + (new GetPropertyAction(PlainRegistry.PASSWORD_FILE, + PlainRegistry.DEFAULT_PASSWORD_FILE)); + } + private Hashtable entries; + private File passwdFile; + private long lastmod; + + public PasswordFile() throws IOException + { + this(DEFAULT_FILE); + } + + public PasswordFile(File pwFile) throws IOException + { + this(pwFile.getAbsolutePath()); + } + + public PasswordFile(String fileName) throws IOException + { + passwdFile = new File(fileName); + update(); + } + + public synchronized void add(String user, String passwd, String[] attributes) + throws IOException + { + checkCurrent(); + if (entries.containsKey(user)) + throw new UserAlreadyExistsException(user); + if (attributes.length != 5) + throw new IllegalArgumentException("Wrong number of attributes"); + // create the new entry + String[] fields = new String[7]; + fields[0] = user; + fields[1] = passwd; + System.arraycopy(attributes, 0, fields, 2, 5); + entries.put(user, fields); + savePasswd(); + } + + public synchronized void changePasswd(String user, String passwd) + throws IOException + { + checkCurrent(); + if (! entries.containsKey(user)) + throw new NoSuchUserException(user); + String[] fields = (String[]) entries.get(user); // get the existing entry + fields[1] = passwd; // modify the password field + entries.remove(user); // delete the existing entry + entries.put(user, fields); // add the new entry + savePasswd(); + } + + public synchronized String[] lookup(String user) throws IOException + { + checkCurrent(); + if (! entries.containsKey(user)) + throw new NoSuchUserException(user); + return (String[]) entries.get(user); + } + + public synchronized boolean contains(String s) throws IOException + { + checkCurrent(); + return entries.containsKey(s); + } + + private synchronized void update() throws IOException + { + lastmod = passwdFile.lastModified(); + readPasswd(new FileInputStream(passwdFile)); + } + + private void checkCurrent() throws IOException + { + if (passwdFile.lastModified() > lastmod) + update(); + } + + private synchronized void readPasswd(InputStream in) throws IOException + { + BufferedReader din = new BufferedReader(new InputStreamReader(in)); + String line; + entries = new Hashtable(); + String[] fields = new String[7]; + while ((line = din.readLine()) != null) + { + StringTokenizer st = new StringTokenizer(line, ":", true); + try + { + fields[0] = st.nextToken(); // username + st.nextToken(); + fields[1] = st.nextToken(); // passwd + if (fields[1].equals(":")) + fields[1] = ""; + else + st.nextToken(); + fields[2] = st.nextToken(); // uid + if (fields[2].equals(":")) + fields[2] = ""; + else + st.nextToken(); + fields[3] = st.nextToken(); // gid + if (fields[3].equals(":")) + fields[3] = ""; + else + st.nextToken(); + fields[4] = st.nextToken(); // gecos + if (fields[4].equals(":")) + fields[4] = ""; + else + st.nextToken(); + fields[5] = st.nextToken(); // dir + if (fields[5].equals(":")) + fields[5] = ""; + else + st.nextToken(); + fields[6] = st.nextToken(); // shell + if (fields[6].equals(":")) + fields[6] = ""; + } + catch (NoSuchElementException ignored) + { + continue; + } + entries.put(fields[0], fields); + } + } + + private synchronized void savePasswd() throws IOException + { + if (passwdFile != null) + { + FileOutputStream fos = new FileOutputStream(passwdFile); + PrintWriter pw = null; + try + { + pw = new PrintWriter(fos); + String key; + String[] fields; + CPStringBuilder sb; + Enumeration keys = entries.keys(); + while (keys.hasMoreElements()) + { + key = (String) keys.nextElement(); + fields = (String[]) entries.get(key); + sb = new CPStringBuilder(fields[0]); + for (int i = 1; i < fields.length; i++) + sb.append(":" + fields[i]); + pw.println(sb.toString()); + } + } + finally + { + if (pw != null) + try + { + pw.flush(); + } + finally + { + pw.close(); + } + if (fos != null) + try + { + fos.close(); + } + catch (IOException ignored) + { + } + lastmod = passwdFile.lastModified(); + } + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainAuthInfoProvider.java b/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainAuthInfoProvider.java new file mode 100644 index 000000000..5f35c455b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainAuthInfoProvider.java @@ -0,0 +1,166 @@ +/* PlainAuthInfoProvider.java -- + Copyright (C) 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.crypto.sasl.plain; + +import gnu.java.security.Registry; +import gnu.javax.crypto.sasl.IAuthInfoProvider; +import gnu.javax.crypto.sasl.NoSuchUserException; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import javax.security.sasl.AuthenticationException; + +/** + * The PLAIN mechanism authentication information provider implementation. + */ +public class PlainAuthInfoProvider + implements IAuthInfoProvider, PlainRegistry +{ + private PasswordFile passwordFile = null; + + // implicit 0-args constrcutor + + public void activate(Map context) throws AuthenticationException + { + try + { + if (context == null) + passwordFile = new PasswordFile(); + else + { + String pfn = (String) context.get(PASSWORD_FILE); + if (pfn == null) + passwordFile = new PasswordFile(); + else + passwordFile = new PasswordFile(pfn); + } + } + catch (IOException x) + { + throw new AuthenticationException("activate()", x); + } + } + + public void passivate() throws AuthenticationException + { + passwordFile = null; + } + + public boolean contains(String userName) throws AuthenticationException + { + if (passwordFile == null) + throw new AuthenticationException("contains()", + new IllegalStateException()); + boolean result = false; + try + { + result = passwordFile.contains(userName); + } + catch (IOException x) + { + throw new AuthenticationException("contains()", x); + } + return result; + } + + public Map lookup(Map userID) throws AuthenticationException + { + if (passwordFile == null) + throw new AuthenticationException("lookup()", new IllegalStateException()); + Map result = new HashMap(); + try + { + String userName = (String) userID.get(Registry.SASL_USERNAME); + if (userName == null) + throw new NoSuchUserException(""); + String[] data = passwordFile.lookup(userName); + result.put(Registry.SASL_USERNAME, data[0]); + result.put(Registry.SASL_PASSWORD, data[1]); + result.put(UID_FIELD, data[2]); + result.put(GID_FIELD, data[3]); + result.put(GECOS_FIELD, data[4]); + result.put(DIR_FIELD, data[5]); + result.put(SHELL_FIELD, data[6]); + } + catch (Exception x) + { + if (x instanceof AuthenticationException) + throw (AuthenticationException) x; + throw new AuthenticationException("lookup()", x); + } + return result; + } + + public void update(Map userCredentials) throws AuthenticationException + { + if (passwordFile == null) + throw new AuthenticationException("update()", new IllegalStateException()); + try + { + String userName = (String) userCredentials.get(Registry.SASL_USERNAME); + String password = (String) userCredentials.get(Registry.SASL_PASSWORD); + String uid = (String) userCredentials.get(UID_FIELD); + String gid = (String) userCredentials.get(GID_FIELD); + String gecos = (String) userCredentials.get(GECOS_FIELD); + String dir = (String) userCredentials.get(DIR_FIELD); + String shell = (String) userCredentials.get(SHELL_FIELD); + if (uid == null || gid == null || gecos == null || dir == null + || shell == null) + passwordFile.changePasswd(userName, password); + else + { + String[] attributes = new String[] { uid, gid, gecos, dir, shell }; + passwordFile.add(userName, password, attributes); + } + } + catch (Exception x) + { + if (x instanceof AuthenticationException) + throw (AuthenticationException) x; + throw new AuthenticationException("update()", x); + } + } + + public Map getConfiguration(String mode) throws AuthenticationException + { + throw new AuthenticationException("", new UnsupportedOperationException()); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainClient.java b/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainClient.java new file mode 100644 index 000000000..f984ed13f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainClient.java @@ -0,0 +1,156 @@ +/* PlainClient.java -- + Copyright (C) 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.crypto.sasl.plain; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.Registry; +import gnu.javax.crypto.sasl.ClientMechanism; + +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslException; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; + +/** + * The PLAIN SASL client-side mechanism. + */ +public class PlainClient + extends ClientMechanism + implements SaslClient +{ + public PlainClient() + { + super(Registry.SASL_PLAIN_MECHANISM); + } + + protected void initMechanism() throws SaslException + { + } + + protected void resetMechanism() throws SaslException + { + } + + public boolean hasInitialResponse() + { + return true; + } + + public byte[] evaluateChallenge(final byte[] challenge) throws SaslException + { + try + { + final String username; + final char[] password; + Callback[] callbacks; + if ((! properties.containsKey(Registry.SASL_USERNAME)) + && (! properties.containsKey(Registry.SASL_PASSWORD))) + { + callbacks = new Callback[2]; + final NameCallback nameCB; + final String defaultName = System.getProperty("user.name"); + if (defaultName == null) + nameCB = new NameCallback("username: "); + else + nameCB = new NameCallback("username: ", defaultName); + final PasswordCallback pwdCB = new PasswordCallback("password: ", + false); + callbacks[0] = nameCB; + callbacks[1] = pwdCB; + this.handler.handle(callbacks); + username = nameCB.getName(); + password = pwdCB.getPassword(); + } + else + { + if (properties.containsKey(Registry.SASL_USERNAME)) + username = (String) properties.get(Registry.SASL_USERNAME); + else + { + callbacks = new Callback[1]; + final NameCallback nameCB; + final String defaultName = System.getProperty("user.name"); + if (defaultName == null) + nameCB = new NameCallback("username: "); + else + nameCB = new NameCallback("username: ", defaultName); + callbacks[0] = nameCB; + this.handler.handle(callbacks); + username = nameCB.getName(); + } + if (properties.containsKey(Registry.SASL_PASSWORD)) + password = ((String) properties.get(Registry.SASL_PASSWORD)).toCharArray(); + else + { + callbacks = new Callback[1]; + final PasswordCallback pwdCB = new PasswordCallback("password: ", + false); + callbacks[0] = pwdCB; + this.handler.handle(callbacks); + password = pwdCB.getPassword(); + } + } + if (password == null) + throw new SaslException("null password supplied"); + final CPStringBuilder sb = new CPStringBuilder(); + if (authorizationID != null) + sb.append(authorizationID); + sb.append('\0'); + sb.append(username); + sb.append('\0'); + sb.append(password); + this.complete = true; + final byte[] response = sb.toString().getBytes("UTF-8"); + return response; + } + catch (Exception x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new SaslException("evaluateChallenge()", x); + } + } + + protected String getNegotiatedQOP() + { + return Registry.QOP_AUTH; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainRegistry.java b/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainRegistry.java new file mode 100644 index 000000000..68b121d96 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainRegistry.java @@ -0,0 +1,57 @@ +/* PlainRegistry.java -- + Copyright (C) 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.crypto.sasl.plain; + +public interface PlainRegistry +{ + /** Name of PLAIN password file property. */ + String PASSWORD_FILE = "gnu.crypto.sasl.plain.password.file"; + /** Default fully qualified pathname of the PLAIN password file. */ + String DEFAULT_PASSWORD_FILE = "/etc/tpasswd"; + /** Name of the UID field in the plain password file. */ + String UID_FIELD = "plain.uid"; + /** Name of the GID field in the plain password file. */ + String GID_FIELD = "plain.gid"; + /** Name of the GECOS field in the plain password file. */ + String GECOS_FIELD = "plain.gecos"; + /** Name of the DIR field in the plain password file. */ + String DIR_FIELD = "plain.dir"; + /** Name of the SHELL field in the plain password file. */ + String SHELL_FIELD = "plain.shell"; +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainServer.java b/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainServer.java new file mode 100644 index 000000000..9d97bc029 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainServer.java @@ -0,0 +1,155 @@ +/* PlainServer.java -- + Copyright (C) 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.crypto.sasl.plain; + +import gnu.java.security.Registry; +import gnu.javax.crypto.sasl.NoSuchUserException; +import gnu.javax.crypto.sasl.ServerMechanism; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.StringTokenizer; + +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +/** + * The PLAIN SASL server-side mechanism. + */ +public class PlainServer + extends ServerMechanism + implements SaslServer +{ + public PlainServer() + { + super(Registry.SASL_PLAIN_MECHANISM); + } + + protected void initMechanism() throws SaslException + { + } + + protected void resetMechanism() throws SaslException + { + } + + public byte[] evaluateResponse(final byte[] response) throws SaslException + { + if (response == null) + return null; + try + { + final String nullStr = new String("\0"); + final StringTokenizer strtok = new StringTokenizer(new String(response), + nullStr, true); + authorizationID = strtok.nextToken(); + if (! authorizationID.equals(nullStr)) + strtok.nextToken(); + else + authorizationID = null; + final String id = strtok.nextToken(); + if (id.equals(nullStr)) + throw new SaslException("No identity given"); + if (authorizationID == null) + authorizationID = id; + if ((! authorizationID.equals(nullStr)) && (! authorizationID.equals(id))) + throw new SaslException("Delegation not supported"); + strtok.nextToken(); + final byte[] pwd; + try + { + pwd = strtok.nextToken().getBytes("UTF-8"); + } + catch (UnsupportedEncodingException x) + { + throw new SaslException("evaluateResponse()", x); + } + if (pwd == null) + throw new SaslException("No password given"); + final byte[] password; + try + { + password = new String(lookupPassword(id)).getBytes("UTF-8"); + } + catch (UnsupportedEncodingException x) + { + throw new SaslException("evaluateResponse()", x); + } + if (! Arrays.equals(pwd, password)) + throw new SaslException("Password incorrect"); + this.complete = true; + return null; + } + catch (NoSuchElementException x) + { + throw new SaslException("evaluateResponse()", x); + } + } + + protected String getNegotiatedQOP() + { + return Registry.QOP_AUTH; + } + + private char[] lookupPassword(final String userName) throws SaslException + { + try + { + if (! authenticator.contains(userName)) + throw new NoSuchUserException(userName); + final Map userID = new HashMap(); + userID.put(Registry.SASL_USERNAME, userName); + final Map credentials = authenticator.lookup(userID); + final String password = (String) credentials.get(Registry.SASL_PASSWORD); + if (password == null) + throw new SaslException("lookupPassword()", new InternalError()); + return password.toCharArray(); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new SaslException("lookupPassword()", x); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/CALG.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/CALG.java new file mode 100644 index 000000000..22f9c9751 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/CALG.java @@ -0,0 +1,221 @@ +/* CALG.java -- + Copyright (C) 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.crypto.sasl.srp; + +import gnu.java.security.Registry; +import gnu.javax.crypto.assembly.Assembly; +import gnu.javax.crypto.assembly.Cascade; +import gnu.javax.crypto.assembly.Direction; +import gnu.javax.crypto.assembly.Stage; +import gnu.javax.crypto.assembly.Transformer; +import gnu.javax.crypto.assembly.TransformerException; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.mode.ModeFactory; +import gnu.javax.crypto.pad.IPad; +import gnu.javax.crypto.pad.PadFactory; +import gnu.javax.crypto.sasl.ConfidentialityException; + +import java.util.HashMap; + +import javax.security.sasl.SaslException; + +/** + * A Factory class that returns CALG (Confidentiality Algorithm) instances that + * operate as described in the draft-burdis-cat-sasl-srp-08. + *

+ * The designated CALG block cipher should be used in OFB (Output Feedback + * Block) mode in the ISO variant, as described in The Handbook of Applied + * Cryptography, algorithm 7.20. + *

+ * Let k be the block size of the chosen symmetric key block + * cipher algorithm; e.g. for AES this is 128 bits or + * 16 octets. The OFB mode used shall be of length/size + * k. + *

+ * It is recommended that block ciphers operating in OFB mode be used with an + * Initial Vector (the mode's IV). In such a mode of operation - OFB with key + * re-use - the IV need not be secret. For the mechanism in question the IVs + * shall be a random octet sequence of k bytes. + *

+ * The input data to the confidentiality protection algorithm shall be a + * multiple of the symmetric cipher block size k. When the input + * length is not a multiple of k octets, the data shall be padded + * according to the following scheme: + *

+ * Assuming the length of the input is l octets, + * (k - (l mod k)) octets, all having the value + * (k - (l mod k)), shall be appended to the original data. In + * other words, the input is padded at the trailing end with one of the + * following sequences: + *

+ *
+ *                     01 -- if l mod k = k-1
+ *                    02 02 -- if l mod k = k-2
+ *                              ...
+ *                              ...
+ *                              ...
+ *                  k k ... k k -- if l mod k = 0
+ * 
+ *

+ * The padding can be removed unambiguously since all input is padded and no + * padding sequence is a suffix of another. This padding method is well-defined + * if and only if k < 256 octets, which is the case with + * symmetric key block ciphers today, and in the forseeable future. + */ +public final class CALG +{ + private Assembly assembly; + private Object modeNdx; // initialisation key of the cascade's attributes + private int blockSize; // the underlying cipher's blocksize == IV length + private int keySize; // the underlying cipher's key size (in bytes). + + /** Private constructor to enforce instantiation through Factory method. */ + private CALG(final int blockSize, final int keySize, final Object modeNdx, + final Assembly assembly) + { + super(); + + this.blockSize = blockSize; + this.keySize = keySize; + this.modeNdx = modeNdx; + this.assembly = assembly; + } + + /** + * Returns an instance of a SASL-SRP CALG implementation. + * + * @param algorithm the name of the symmetric cipher algorithm. + * @return an instance of this object. + */ + static synchronized CALG getInstance(final String algorithm) + { + final IBlockCipher cipher = CipherFactory.getInstance(algorithm); + final int blockSize = cipher.defaultBlockSize(); + final int keySize = cipher.defaultKeySize(); + final Cascade ofbCipher = new Cascade(); + IMode ofbMode = ModeFactory.getInstance(Registry.OFB_MODE, + cipher, + blockSize); + Stage modeStage = Stage.getInstance(ofbMode, Direction.FORWARD); + final Object modeNdx = ofbCipher.append(modeStage); + final IPad pkcs7 = PadFactory.getInstance(Registry.PKCS7_PAD); + final Assembly asm = new Assembly(); + asm.addPreTransformer(Transformer.getCascadeTransformer(ofbCipher)); + asm.addPreTransformer(Transformer.getPaddingTransformer(pkcs7)); + return new CALG(blockSize, keySize, modeNdx, asm); + } + + /** + * Initialises a SASL-SRP CALG implementation. + * + * @param kdf the key derivation function. + * @param iv the initial vector value to use. + * @param dir whether this CALG is used for encryption or decryption. + */ + public void init(final KDF kdf, final byte[] iv, final Direction dir) + throws SaslException + { + final byte[] realIV; + if (iv.length == blockSize) + realIV = iv; + else + { + realIV = new byte[blockSize]; + if (iv.length > blockSize) + System.arraycopy(iv, 0, realIV, 0, blockSize); + else // shouldnt happen + System.arraycopy(iv, 0, realIV, 0, iv.length); + } + final HashMap modeAttributes = new HashMap(); + final byte[] sk = kdf.derive(keySize); + modeAttributes.put(IBlockCipher.KEY_MATERIAL, sk); + modeAttributes.put(IMode.IV, realIV); + final HashMap attributes = new HashMap(); + attributes.put(Assembly.DIRECTION, dir); + attributes.put(modeNdx, modeAttributes); + try + { + assembly.init(attributes); + } + catch (TransformerException x) + { + throw new SaslException("getInstance()", x); + } + } + + /** + * Encrypts or decrypts, depending on the mode already set, a designated array + * of bytes and returns the result. + * + * @param data the data to encrypt/decrypt. + * @return the decrypted/encrypted result. + * @throws ConfidentialityException if an exception occurs duirng the process. + */ + public byte[] doFinal(final byte[] data) throws ConfidentialityException + { + return doFinal(data, 0, data.length); + } + + /** + * Encrypts or decrypts, depending on the mode already set, a designated array + * of bytes and returns the result. + * + * @param data the data to encrypt/decrypt. + * @param offset where to start in data. + * @param length how many bytes to consider in data. + * @return the decrypted/encrypted result. + * @throws ConfidentialityException if an exception occurs duirng the process. + */ + public byte[] doFinal(final byte[] data, final int offset, final int length) + throws ConfidentialityException + { + final byte[] result; + try + { + result = assembly.lastUpdate(data, offset, length); + } + catch (TransformerException x) + { + throw new ConfidentialityException("doFinal()", x); + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/ClientStore.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/ClientStore.java new file mode 100644 index 000000000..1d27137d1 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/ClientStore.java @@ -0,0 +1,155 @@ +/* ClientStore.java -- + Copyright (C) 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.crypto.sasl.srp; + +import java.util.HashMap; + +/** + * The client-side implementation of the SRP security context store. + */ +public class ClientStore +{ + /** The underlying singleton. */ + private static ClientStore singleton = null; + /** The map of uid --> SASL Security Context record. */ + private static final HashMap uid2ssc = new HashMap(); + /** The map of sid --> Session timing record. */ + private static final HashMap uid2ttl = new HashMap(); + /** A synchronisation lock. */ + private static final Object lock = new Object(); + + /** Private constructor to enforce Singleton pattern. */ + private ClientStore() + { + super(); + + // TODO: add a cleaning timer thread + } + + /** + * Returns the classloader Singleton. + * + * @return the classloader Singleton instance. + */ + static synchronized final ClientStore instance() + { + if (singleton == null) + singleton = new ClientStore(); + return singleton; + } + + /** + * Returns a boolean flag indicating if the designated client's session is + * still alive or not. + * + * @param uid the identifier of the client whose session to check. + * @return true if the designated client's session is still + * alive. false otherwise. + */ + boolean isAlive(final String uid) + { + final boolean result; + synchronized (lock) + { + final Object obj = uid2ssc.get(uid); + result = (obj != null); + if (result) // is it still alive? + { + final StoreEntry sto = (StoreEntry) uid2ttl.get(uid); + if (! sto.isAlive()) // invalidate it + { + uid2ssc.remove(uid); + uid2ttl.remove(uid); + } + } + } + return result; + } + + /** + * Records a mapping between a client's unique identifier and its security + * context. + * + * @param uid the unique identifier of the SRP client for which the session is + * to be cached. + * @param ttl the session's Time-To-Live indicator (in seconds). + * @param ctx the client's security context. + */ + void cacheSession(final String uid, final int ttl, final SecurityContext ctx) + { + synchronized (lock) + { + uid2ssc.put(uid, ctx); + uid2ttl.put(uid, new StoreEntry(ttl)); + } + } + + /** + * Removes the mapping between the designated SRP client unique identifier and + * the its session security context (and other timing information). + * + * @param uid the identifier of the client whose session is to invalidate. + */ + void invalidateSession(final String uid) + { + synchronized (lock) + { + uid2ssc.remove(uid); + uid2ttl.remove(uid); + } + } + + /** + * Returns an SRP client's security context record mapped by that client's + * unique identifier. + * + * @param uid the identifier of the client whose session is to restore. + * @return the SRP client's security context. + */ + SecurityContext restoreSession(final String uid) + { + final SecurityContext result; + synchronized (lock) + { + result = (SecurityContext) uid2ssc.remove(uid); + uid2ttl.remove(uid); + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/IALG.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/IALG.java new file mode 100644 index 000000000..d0c92ea68 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/IALG.java @@ -0,0 +1,128 @@ +/* IALG.java -- + Copyright (C) 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.crypto.sasl.srp; + +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; + +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.HashMap; + +import javax.security.sasl.SaslException; + +/** + * A Factory class that returns IALG (Integrity Algorithm) instances that + * operate as described in the draft-burdis-cat-sasl-srp-04 and later. + */ +public final class IALG + implements Cloneable +{ + private IMac hmac; + + /** Private constructor to enforce instantiation through Factory method. */ + private IALG(final IMac hmac) + { + super(); + + this.hmac = hmac; + } + + /** + * Returns an instance of a SASL-SRP IALG implementation. + * + * @param algorithm the name of the HMAC algorithm. + * @return an instance of this object. + */ + static synchronized IALG getInstance(final String algorithm) + throws SaslException + { + final IMac hmac; + hmac = MacFactory.getInstance(algorithm); + if (hmac == null) + throw new SaslException("getInstance()", + new NoSuchAlgorithmException(algorithm)); + return new IALG(hmac); + } + + public Object clone() throws CloneNotSupportedException + { + return new IALG((IMac) hmac.clone()); + } + + public void init(final KDF kdf) throws SaslException + { + try + { + final byte[] sk = kdf.derive(hmac.macSize()); + final HashMap map = new HashMap(); + map.put(IMac.MAC_KEY_MATERIAL, sk); + hmac.init(map); + } + catch (InvalidKeyException x) + { + throw new SaslException("getInstance()", x); + } + } + + public void update(final byte[] data) + { + hmac.update(data, 0, data.length); + } + + public void update(final byte[] data, final int offset, final int length) + { + hmac.update(data, offset, length); + } + + public byte[] doFinal() + { + return hmac.digest(); + } + + /** + * Returns the length (in bytes) of this SASL SRP Integrity Algorithm. + * + * @return the length, in bytes, of this integrity protection algorithm. + */ + public int length() + { + return hmac.macSize(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/KDF.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/KDF.java new file mode 100644 index 000000000..513aafb94 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/KDF.java @@ -0,0 +1,140 @@ +/* KDF.java -- + Copyright (C) 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.crypto.sasl.srp; + +import gnu.java.security.Registry; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.PRNG; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.prng.UMacGenerator; + +import java.util.HashMap; + +/** + * The SASL-SRP KDF implementation, which is also used, depending on how it was + * instantiated, as a secure Pseudo Random Number Generator. + */ +public class KDF +{ + private static final int AES_BLOCK_SIZE = 16; // default block size for AES + private static final int AES_KEY_SIZE = 16; // default key size for the AES + private static final byte[] buffer = new byte[1]; + /** Our default source of randomness. */ + private static final PRNG prng = PRNG.getInstance(); + /** The underlying UMAC Generator instance. */ + private UMacGenerator umac = null; + + /** + * Constructs an instance of the KDF initialised with the + * designated shared secret bytes. + * + * @param keyMaterial the SASL SRP shared secret (K) bytes. + */ + private KDF(final byte[] keyMaterial, final int ndx) + { + super(); + + final HashMap map = new HashMap(); + map.put(UMacGenerator.CIPHER, Registry.AES_CIPHER); + map.put(UMacGenerator.INDEX, Integer.valueOf(ndx)); + map.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(AES_BLOCK_SIZE)); + final byte[] key = new byte[AES_KEY_SIZE]; + System.arraycopy(keyMaterial, 0, key, 0, AES_KEY_SIZE); + map.put(IBlockCipher.KEY_MATERIAL, key); + umac = new UMacGenerator(); + umac.init(map); + } + + /** + * A Factory mehod that returns an instance of a KDF based on + * supplied seed data. + * + * @param K the SASL SRP shared secret for a KDF to be used for + * CALG and IALG setup. null otherwise. + * @return an instance of a KDF. + */ + static final KDF getInstance(final byte[] K) + { + int ndx = -1; + final byte[] keyMaterial; + if (K != null) + { + keyMaterial = K; + ndx = 0; + } + else + { + keyMaterial = new byte[AES_BLOCK_SIZE]; + while (ndx < 1 || ndx > 255) + ndx = (byte) nextByte(); + } + return new KDF(keyMaterial, ndx); + } + + private static synchronized final int nextByte() + { + prng.nextBytes(buffer); + return (buffer[0] & 0xFF); + } + + /** + * Returns a designated number of bytes suitable for use in the SASL SRP + * mechanism. + * + * @param length the number of bytes needed. + * @return a byte array containing the generated/selected bytes. + */ + public synchronized byte[] derive(final int length) + { + final byte[] result = new byte[length]; + try + { + umac.nextBytes(result, 0, length); + } + catch (IllegalStateException x) // should not happen + { + x.printStackTrace(System.err); + } + catch (LimitReachedException x) // idem + { + x.printStackTrace(System.err); + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/PasswordFile.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/PasswordFile.java new file mode 100644 index 000000000..c13c2fa71 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/PasswordFile.java @@ -0,0 +1,627 @@ +/* PasswordFile.java -- + Copyright (C) 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.crypto.sasl.srp; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; +import gnu.javax.crypto.key.srp6.SRPAlgorithm; +import gnu.javax.crypto.sasl.NoSuchUserException; +import gnu.javax.crypto.sasl.UserAlreadyExistsException; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.util.HashMap; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.StringTokenizer; + +/** + * The implementation of SRP password files. + *

+ * For SRP, there are three (3) files: + *

    + *
  1. The password configuration file: tpasswd.conf. It contains the pairs + * <N,g> indexed by a number for each pair used for a user. By default, this + * file's pathname is constructed from the base password file pathname by + * prepending it with the ".conf" suffix.
  2. + *
  3. The base password file: tpasswd. It contains the related password + * entries for all the users with values computed using SRP's default message + * digest algorithm: SHA-1 (with 160-bit output block size).
  4. + *
  5. The extended password file: tpasswd2. Its name, by default, is + * constructed by adding the suffix "2" to the fully qualified pathname of the + * base password file. It contains, in addition to the same fields as the base + * password file, albeit with a different verifier value, an extra field + * identifying the message digest algorithm used to compute this (verifier) + * value.
  6. + *
+ *

+ * This implementation assumes the following message digest algorithm codes: + *

+ *

+ * IMPORTANT: This method computes the verifiers as described in + * RFC-2945, which differs from the description given on the web page for SRP-6. + *

+ * Reference: + *

    + *
  1. SRP Protocol Design
    + * Thomas J. Wu.
  2. + *
+ */ +public class PasswordFile +{ + // names of property keys used in this class + private static final String USER_FIELD = "user"; + private static final String VERIFIERS_FIELD = "verifier"; + private static final String SALT_FIELD = "salt"; + private static final String CONFIG_FIELD = "config"; + private static String DEFAULT_FILE; + static + { + DEFAULT_FILE = System.getProperty(SRPRegistry.PASSWORD_FILE, + SRPRegistry.DEFAULT_PASSWORD_FILE); + } + /** The SRP algorithm instances used by this object. */ + private static final HashMap srps; + static + { + final HashMap map = new HashMap(SRPRegistry.SRP_ALGORITHMS.length); + // The first entry MUST exist. The others are optional. + map.put("0", SRP.instance(SRPRegistry.SRP_ALGORITHMS[0])); + for (int i = 1; i < SRPRegistry.SRP_ALGORITHMS.length; i++) + { + try + { + map.put(String.valueOf(i), + SRP.instance(SRPRegistry.SRP_ALGORITHMS[i])); + } + catch (Exception x) + { + System.err.println("Ignored: " + x); + x.printStackTrace(System.err); + } + } + srps = map; + } + + private String confName, pwName, pw2Name; + private File configFile, passwdFile, passwd2File; + private long lastmodPasswdFile, lastmodPasswd2File; + private HashMap entries = new HashMap(); + private HashMap configurations = new HashMap(); + // default N values to use when creating a new password.conf file + private static final BigInteger[] Nsrp = new BigInteger[] { + SRPAlgorithm.N_2048, + SRPAlgorithm.N_1536, + SRPAlgorithm.N_1280, + SRPAlgorithm.N_1024, + SRPAlgorithm.N_768, + SRPAlgorithm.N_640, + SRPAlgorithm.N_512 }; + + public PasswordFile() throws IOException + { + this(DEFAULT_FILE); + } + + public PasswordFile(final File pwFile) throws IOException + { + this(pwFile.getAbsolutePath()); + } + + public PasswordFile(final String pwName) throws IOException + { + this(pwName, pwName + "2", pwName + ".conf"); + } + + public PasswordFile(final String pwName, final String confName) + throws IOException + { + this(pwName, pwName + "2", confName); + } + + public PasswordFile(final String pwName, final String pw2Name, + final String confName) throws IOException + { + super(); + + this.pwName = pwName; + this.pw2Name = pw2Name; + this.confName = confName; + + readOrCreateConf(); + update(); + } + + /** + * Returns a string representing the decimal value of an integer identifying + * the message digest algorithm to use for the SRP computations. + * + * @param mdName the canonical name of a message digest algorithm. + * @return a string representing the decimal value of an ID for that + * algorithm. + */ + private static final String nameToID(final String mdName) + { + if (Registry.SHA_HASH.equalsIgnoreCase(mdName) + || Registry.SHA1_HASH.equalsIgnoreCase(mdName) + || Registry.SHA160_HASH.equalsIgnoreCase(mdName)) + return "0"; + else if (Registry.MD5_HASH.equalsIgnoreCase(mdName)) + return "1"; + else if (Registry.RIPEMD128_HASH.equalsIgnoreCase(mdName)) + return "2"; + else if (Registry.RIPEMD160_HASH.equalsIgnoreCase(mdName)) + return "3"; + else if (Registry.SHA256_HASH.equalsIgnoreCase(mdName)) + return "4"; + else if (Registry.SHA384_HASH.equalsIgnoreCase(mdName)) + return "5"; + else if (Registry.SHA512_HASH.equalsIgnoreCase(mdName)) + return "6"; + return "0"; + } + + /** + * Checks if the current configuration file contains the <N, g> pair for + * the designated index. + * + * @param index a string representing 1-digit identification of an <N, g> + * pair used. + * @return true if the designated index is that + * of a known <N, g> pair, and false otherwise. + * @throws IOException if an exception occurs during the process. + * @see SRPRegistry#N_2048_BITS + * @see SRPRegistry#N_1536_BITS + * @see SRPRegistry#N_1280_BITS + * @see SRPRegistry#N_1024_BITS + * @see SRPRegistry#N_768_BITS + * @see SRPRegistry#N_640_BITS + * @see SRPRegistry#N_512_BITS + */ + public synchronized boolean containsConfig(final String index) + throws IOException + { + checkCurrent(); + return configurations.containsKey(index); + } + + /** + * Returns a pair of strings representing the pair of N and + * g MPIs for the designated index. + * + * @param index a string representing 1-digit identification of an <N, g> + * pair to look up. + * @return a pair of strings, arranged in an array, where the first (at index + * position #0) is the repesentation of the MPI N, and + * the second (at index position #1) is the representation of the MPI + * g. If the index refers to an unknown + * pair, then an empty string array is returned. + * @throws IOException if an exception occurs during the process. + */ + public synchronized String[] lookupConfig(final String index) + throws IOException + { + checkCurrent(); + String[] result = null; + if (configurations.containsKey(index)) + result = (String[]) configurations.get(index); + return result; + } + + public synchronized boolean contains(final String user) throws IOException + { + checkCurrent(); + return entries.containsKey(user); + } + + public synchronized void add(final String user, final String passwd, + final byte[] salt, final String index) + throws IOException + { + checkCurrent(); + if (entries.containsKey(user)) + throw new UserAlreadyExistsException(user); + final HashMap fields = new HashMap(4); + fields.put(USER_FIELD, user); // 0 + fields.put(VERIFIERS_FIELD, newVerifiers(user, salt, passwd, index)); // 1 + fields.put(SALT_FIELD, Util.toBase64(salt)); // 2 + fields.put(CONFIG_FIELD, index); // 3 + entries.put(user, fields); + savePasswd(); + } + + public synchronized void changePasswd(final String user, final String passwd) + throws IOException + { + checkCurrent(); + if (! entries.containsKey(user)) + throw new NoSuchUserException(user); + final HashMap fields = (HashMap) entries.get(user); + final byte[] salt; + try + { + salt = Util.fromBase64((String) fields.get(SALT_FIELD)); + } + catch (NumberFormatException x) + { + throw new IOException("Password file corrupt"); + } + final String index = (String) fields.get(CONFIG_FIELD); + fields.put(VERIFIERS_FIELD, newVerifiers(user, salt, passwd, index)); + entries.put(user, fields); + savePasswd(); + } + + public synchronized void savePasswd() throws IOException + { + final FileOutputStream f1 = new FileOutputStream(passwdFile); + final FileOutputStream f2 = new FileOutputStream(passwd2File); + PrintWriter pw1 = null; + PrintWriter pw2 = null; + try + { + pw1 = new PrintWriter(f1, true); + pw2 = new PrintWriter(f2, true); + this.writePasswd(pw1, pw2); + } + finally + { + if (pw1 != null) + try + { + pw1.flush(); + } + finally + { + pw1.close(); + } + if (pw2 != null) + try + { + pw2.flush(); + } + finally + { + pw2.close(); + } + try + { + f1.close(); + } + catch (IOException ignored) + { + } + try + { + f2.close(); + } + catch (IOException ignored) + { + } + } + lastmodPasswdFile = passwdFile.lastModified(); + lastmodPasswd2File = passwd2File.lastModified(); + } + + /** + * Returns the triplet: verifier, salt and configuration file index, of a + * designated user, and a designated message digest algorithm name, as an + * array of strings. + * + * @param user the username. + * @param mdName the canonical name of the SRP's message digest algorithm. + * @return a string array containing, in this order, the BASE-64 encodings of + * the verifier, the salt and the index in the password configuration + * file of the MPIs N and g of the designated user. + */ + public synchronized String[] lookup(final String user, final String mdName) + throws IOException + { + checkCurrent(); + if (! entries.containsKey(user)) + throw new NoSuchUserException(user); + final HashMap fields = (HashMap) entries.get(user); + final HashMap verifiers = (HashMap) fields.get(VERIFIERS_FIELD); + final String salt = (String) fields.get(SALT_FIELD); + final String index = (String) fields.get(CONFIG_FIELD); + final String verifier = (String) verifiers.get(nameToID(mdName)); + return new String[] { verifier, salt, index }; + } + + private synchronized void readOrCreateConf() throws IOException + { + configurations.clear(); + final FileInputStream fis; + configFile = new File(confName); + try + { + fis = new FileInputStream(configFile); + readConf(fis); + } + catch (FileNotFoundException x) + { // create a default one + final String g = Util.toBase64(Util.trim(new BigInteger("2"))); + String index, N; + for (int i = 0; i < Nsrp.length; i++) + { + index = String.valueOf(i + 1); + N = Util.toBase64(Util.trim(Nsrp[i])); + configurations.put(index, new String[] { N, g }); + } + FileOutputStream f0 = null; + PrintWriter pw0 = null; + try + { + f0 = new FileOutputStream(configFile); + pw0 = new PrintWriter(f0, true); + this.writeConf(pw0); + } + finally + { + if (pw0 != null) + pw0.close(); + else if (f0 != null) + f0.close(); + } + } + } + + private void readConf(final InputStream in) throws IOException + { + final BufferedReader din = new BufferedReader(new InputStreamReader(in)); + String line, index, N, g; + StringTokenizer st; + while ((line = din.readLine()) != null) + { + st = new StringTokenizer(line, ":"); + try + { + index = st.nextToken(); + N = st.nextToken(); + g = st.nextToken(); + } + catch (NoSuchElementException x) + { + throw new IOException("SRP password configuration file corrupt"); + } + configurations.put(index, new String[] { N, g }); + } + } + + private void writeConf(final PrintWriter pw) + { + String ndx; + String[] mpi; + CPStringBuilder sb; + for (Iterator it = configurations.keySet().iterator(); it.hasNext();) + { + ndx = (String) it.next(); + mpi = (String[]) configurations.get(ndx); + sb = new CPStringBuilder(ndx) + .append(":").append(mpi[0]) + .append(":").append(mpi[1]); + pw.println(sb.toString()); + } + } + + /** + * Compute the new verifiers for the designated username and password. + *

+ * IMPORTANT: This method computes the verifiers as described in + * RFC-2945, which differs from the description given on the web page for + * SRP-6. + * + * @param user the user's name. + * @param s the user's salt. + * @param password the user's password + * @param index the index of the <N, g> pair to use for this user. + * @return a {@link java.util.Map} of user verifiers. + * @throws UnsupportedEncodingException if the US-ASCII decoder is not + * available on this platform. + */ + private HashMap newVerifiers(final String user, final byte[] s, + final String password, final String index) + throws UnsupportedEncodingException + { + // to ensure inter-operability with non-java tools + final String[] mpi = (String[]) configurations.get(index); + final BigInteger N = new BigInteger(1, Util.fromBase64(mpi[0])); + final BigInteger g = new BigInteger(1, Util.fromBase64(mpi[1])); + final HashMap result = new HashMap(srps.size()); + BigInteger x, v; + SRP srp; + for (int i = 0; i < srps.size(); i++) + { + final String digestID = String.valueOf(i); + srp = (SRP) srps.get(digestID); + x = new BigInteger(1, srp.computeX(s, user, password)); + v = g.modPow(x, N); + final String verifier = Util.toBase64(v.toByteArray()); + result.put(digestID, verifier); + } + return result; + } + + private synchronized void update() throws IOException + { + entries.clear(); + FileInputStream fis; + passwdFile = new File(pwName); + lastmodPasswdFile = passwdFile.lastModified(); + try + { + fis = new FileInputStream(passwdFile); + readPasswd(fis); + } + catch (FileNotFoundException ignored) + { + } + passwd2File = new File(pw2Name); + lastmodPasswd2File = passwd2File.lastModified(); + try + { + fis = new FileInputStream(passwd2File); + readPasswd2(fis); + } + catch (FileNotFoundException ignored) + { + } + } + + private void checkCurrent() throws IOException + { + if (passwdFile.lastModified() > lastmodPasswdFile + || passwd2File.lastModified() > lastmodPasswd2File) + update(); + } + + private void readPasswd(final InputStream in) throws IOException + { + final BufferedReader din = new BufferedReader(new InputStreamReader(in)); + String line, user, verifier, salt, index; + StringTokenizer st; + while ((line = din.readLine()) != null) + { + st = new StringTokenizer(line, ":"); + try + { + user = st.nextToken(); + verifier = st.nextToken(); + salt = st.nextToken(); + index = st.nextToken(); + } + catch (NoSuchElementException x) + { + throw new IOException("SRP base password file corrupt"); + } + final HashMap verifiers = new HashMap(6); + verifiers.put("0", verifier); + final HashMap fields = new HashMap(4); + fields.put(USER_FIELD, user); + fields.put(VERIFIERS_FIELD, verifiers); + fields.put(SALT_FIELD, salt); + fields.put(CONFIG_FIELD, index); + entries.put(user, fields); + } + } + + private void readPasswd2(final InputStream in) throws IOException + { + final BufferedReader din = new BufferedReader(new InputStreamReader(in)); + String line, digestID, user, verifier; + StringTokenizer st; + HashMap fields, verifiers; + while ((line = din.readLine()) != null) + { + st = new StringTokenizer(line, ":"); + try + { + digestID = st.nextToken(); + user = st.nextToken(); + verifier = st.nextToken(); + } + catch (NoSuchElementException x) + { + throw new IOException("SRP extended password file corrupt"); + } + fields = (HashMap) entries.get(user); + if (fields != null) + { + verifiers = (HashMap) fields.get(VERIFIERS_FIELD); + verifiers.put(digestID, verifier); + } + } + } + + private void writePasswd(final PrintWriter pw1, final PrintWriter pw2) + throws IOException + { + String user, digestID; + HashMap fields, verifiers; + CPStringBuilder sb1, sb2; + Iterator j; + final Iterator i = entries.keySet().iterator(); + while (i.hasNext()) + { + user = (String) i.next(); + fields = (HashMap) entries.get(user); + if (! user.equals(fields.get(USER_FIELD))) + throw new IOException("Inconsistent SRP password data"); + verifiers = (HashMap) fields.get(VERIFIERS_FIELD); + sb1 = new CPStringBuilder(user) + .append(":").append((String) verifiers.get("0")) + .append(":").append((String) fields.get(SALT_FIELD)) + .append(":").append((String) fields.get(CONFIG_FIELD)); + pw1.println(sb1.toString()); + // write extended information + j = verifiers.keySet().iterator(); + while (j.hasNext()) + { + digestID = (String) j.next(); + if (! "0".equals(digestID)) + { + // #0 is the default digest, already present in tpasswd! + sb2 = new CPStringBuilder(digestID) + .append(":").append(user) + .append(":").append((String) verifiers.get(digestID)); + pw2.println(sb2.toString()); + } + } + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/SRP.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRP.java new file mode 100644 index 000000000..569855dd7 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRP.java @@ -0,0 +1,255 @@ +/* SRP.java -- + Copyright (C) 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.crypto.sasl.srp; + +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.util.Util; + +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.util.HashMap; + +/** + * A Factory class that returns SRP Singletons that know all SRP-related + * mathematical computations and protocol-related operations for both the + * client- and server-sides. + */ +public final class SRP +{ + /** The map of already instantiated SRP algorithm instances. */ + private static final HashMap algorithms = new HashMap(); + private static final byte COLON = (byte) 0x3A; + /** The underlying message digest algorithm used for all SRP calculations. */ + private IMessageDigest mda; + + /** Trivial private constructor to enforce Singleton pattern. */ + private SRP(final IMessageDigest mda) + { + super(); + + this.mda = mda; + } + + /** + * Returns an instance of this object that uses the designated message digest + * algorithm as its digest function. + * + * @return an instance of this object for the designated digest name. + */ + public static synchronized SRP instance(String mdName) + { + if (mdName != null) + mdName = mdName.trim().toLowerCase(); + if (mdName == null || mdName.equals("")) + mdName = SRPRegistry.SRP_DEFAULT_DIGEST_NAME; + SRP result = (SRP) algorithms.get(mdName); + if (result == null) + { + final IMessageDigest mda = HashFactory.getInstance(mdName); + result = new SRP(mda); + algorithms.put(mdName, result); + } + return result; + } + + private static final byte[] xor(final byte[] b1, final byte[] b2, + final int length) + { + final byte[] result = new byte[length]; + for (int i = 0; i < length; ++i) + result[i] = (byte)(b1[i] ^ b2[i]); + return result; + } + + /** @return the message digest algorithm name used by this instance. */ + public String getAlgorithm() + { + return mda.name(); + } + + /** + * Returns a new instance of the SRP message digest algorithm --which is + * SHA-160 by default, but could be anything else provided the proper + * conditions as specified in the SRP specifications. + * + * @return a new instance of the underlying SRP message digest algorithm. + * @throws RuntimeException if the implementation of the message digest + * algorithm does not support cloning. + */ + public IMessageDigest newDigest() + { + return (IMessageDigest) mda.clone(); + } + + /** + * Convenience method to return the result of digesting the designated input + * with a new instance of the SRP message digest algorithm. + * + * @param src some bytes to digest. + * @return the bytes constituting the result of digesting the designated input + * with a new instance of the SRP message digest algorithm. + */ + public byte[] digest(final byte[] src) + { + final IMessageDigest hash = (IMessageDigest) mda.clone(); + hash.update(src, 0, src.length); + return hash.digest(); + } + + /** + * Convenience method to return the result of digesting the designated input + * with a new instance of the SRP message digest algorithm. + * + * @param src a String whose bytes (using US-ASCII encoding) are to be + * digested. + * @return the bytes constituting the result of digesting the designated input + * with a new instance of the SRP message digest algorithm. + * @throws UnsupportedEncodingException if US-ASCII charset is not found. + */ + public byte[] digest(final String src) throws UnsupportedEncodingException + { + return digest(src.getBytes("US-ASCII")); + } + + /** + * Convenience method to XOR N bytes from two arrays; N being the output size + * of the SRP message digest algorithm. + * + * @param a the first byte array. + * @param b the second one. + * @return N bytes which are the result of the XOR operations on the first N + * bytes from the designated arrays. N is the size of the SRP message + * digest algorithm; eg. 20 for SHA-160. + */ + public byte[] xor(final byte[] a, final byte[] b) + { + return xor(a, b, mda.hashSize()); + } + + public byte[] generateM1(final BigInteger N, final BigInteger g, + final String U, final byte[] s, final BigInteger A, + final BigInteger B, final byte[] K, final String I, + final String L, final byte[] cn, final byte[] cCB) + throws UnsupportedEncodingException + { + final IMessageDigest hash = (IMessageDigest) mda.clone(); + byte[] b; + b = xor(digest(Util.trim(N)), digest(Util.trim(g))); + hash.update(b, 0, b.length); + b = digest(U); + hash.update(b, 0, b.length); + hash.update(s, 0, s.length); + b = Util.trim(A); + hash.update(b, 0, b.length); + b = Util.trim(B); + hash.update(b, 0, b.length); + hash.update(K, 0, K.length); + b = digest(I); + hash.update(b, 0, b.length); + b = digest(L); + hash.update(b, 0, b.length); + hash.update(cn, 0, cn.length); + hash.update(cCB, 0, cCB.length); + return hash.digest(); + } + + public byte[] generateM2(final BigInteger A, final byte[] M1, final byte[] K, + final String U, final String I, final String o, + final byte[] sid, final int ttl, final byte[] cIV, + final byte[] sIV, final byte[] sCB) + throws UnsupportedEncodingException + { + final IMessageDigest hash = (IMessageDigest) mda.clone(); + byte[] b; + b = Util.trim(A); + hash.update(b, 0, b.length); + hash.update(M1, 0, M1.length); + hash.update(K, 0, K.length); + b = digest(U); + hash.update(b, 0, b.length); + b = digest(I); + hash.update(b, 0, b.length); + b = digest(o); + hash.update(b, 0, b.length); + hash.update(sid, 0, sid.length); + hash.update((byte)(ttl >>> 24)); + hash.update((byte)(ttl >>> 16)); + hash.update((byte)(ttl >>> 8)); + hash.update((byte) ttl); + hash.update(cIV, 0, cIV.length); + hash.update(sIV, 0, sIV.length); + hash.update(sCB, 0, sCB.length); + return hash.digest(); + } + + public byte[] generateKn(final byte[] K, final byte[] cn, final byte[] sn) + { + final IMessageDigest hash = (IMessageDigest) mda.clone(); + hash.update(K, 0, K.length); + hash.update(cn, 0, cn.length); + hash.update(sn, 0, sn.length); + return hash.digest(); + } + + public byte[] computeX(final byte[] s, final String user, + final String password) + throws UnsupportedEncodingException + { + return computeX(s, user.getBytes("US-ASCII"), password.getBytes("US-ASCII")); + } + + public byte[] computeX(final byte[] s, final String user, final byte[] p) + throws UnsupportedEncodingException + { + return computeX(s, user.getBytes("US-ASCII"), p); + } + + private byte[] computeX(final byte[] s, final byte[] user, final byte[] p) + { + final IMessageDigest hash = (IMessageDigest) mda.clone(); + hash.update(user, 0, user.length); + hash.update(COLON); + hash.update(p, 0, p.length); + final byte[] up = hash.digest(); + hash.update(s, 0, s.length); + hash.update(up, 0, up.length); + return hash.digest(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPAuthInfoProvider.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPAuthInfoProvider.java new file mode 100644 index 000000000..e42cfffa9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPAuthInfoProvider.java @@ -0,0 +1,177 @@ +/* SRPAuthInfoProvider.java -- + Copyright (C) 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.crypto.sasl.srp; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; +import gnu.javax.crypto.sasl.IAuthInfoProvider; +import gnu.javax.crypto.sasl.NoSuchUserException; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import javax.security.sasl.AuthenticationException; + +/** + * The SRP mechanism authentication information provider implementation. + */ +public class SRPAuthInfoProvider + implements IAuthInfoProvider +{ + private PasswordFile passwordFile = null; + + // implicit 0-args constrcutor + + public void activate(Map context) throws AuthenticationException + { + try + { + if (context == null) + passwordFile = new PasswordFile(); + else + { + passwordFile = (PasswordFile) context.get(SRPRegistry.PASSWORD_DB); + if (passwordFile == null) + { + String pfn = (String) context.get(SRPRegistry.PASSWORD_FILE); + if (pfn == null) + passwordFile = new PasswordFile(); + else + passwordFile = new PasswordFile(pfn); + } + } + } + catch (IOException x) + { + throw new AuthenticationException("activate()", x); + } + } + + public void passivate() throws AuthenticationException + { + passwordFile = null; + } + + public boolean contains(String userName) throws AuthenticationException + { + if (passwordFile == null) + throw new AuthenticationException("contains()", + new IllegalStateException()); + boolean result = false; + try + { + result = passwordFile.contains(userName); + } + catch (IOException x) + { + throw new AuthenticationException("contains()", x); + } + return result; + } + + public Map lookup(Map userID) throws AuthenticationException + { + if (passwordFile == null) + throw new AuthenticationException("lookup()", new IllegalStateException()); + Map result = new HashMap(); + try + { + String userName = (String) userID.get(Registry.SASL_USERNAME); + if (userName == null) + throw new NoSuchUserException(""); + String mdName = (String) userID.get(SRPRegistry.MD_NAME_FIELD); + String[] data = passwordFile.lookup(userName, mdName); + result.put(SRPRegistry.USER_VERIFIER_FIELD, data[0]); + result.put(SRPRegistry.SALT_FIELD, data[1]); + result.put(SRPRegistry.CONFIG_NDX_FIELD, data[2]); + } + catch (Exception x) + { + if (x instanceof AuthenticationException) + throw (AuthenticationException) x; + throw new AuthenticationException("lookup()", x); + } + return result; + } + + public void update(Map userCredentials) throws AuthenticationException + { + if (passwordFile == null) + throw new AuthenticationException("update()", new IllegalStateException()); + try + { + String userName = (String) userCredentials.get(Registry.SASL_USERNAME); + String password = (String) userCredentials.get(Registry.SASL_PASSWORD); + String salt = (String) userCredentials.get(SRPRegistry.SALT_FIELD); + String config = (String) userCredentials.get(SRPRegistry.CONFIG_NDX_FIELD); + if (salt == null || config == null) + passwordFile.changePasswd(userName, password); + else + passwordFile.add(userName, password, Util.fromBase64(salt), config); + } + catch (Exception x) + { + if (x instanceof AuthenticationException) + throw (AuthenticationException) x; + throw new AuthenticationException("update()", x); + } + } + + public Map getConfiguration(String mode) throws AuthenticationException + { + if (passwordFile == null) + throw new AuthenticationException("getConfiguration()", + new IllegalStateException()); + Map result = new HashMap(); + try + { + String[] data = passwordFile.lookupConfig(mode); + result.put(SRPRegistry.SHARED_MODULUS, data[0]); + result.put(SRPRegistry.FIELD_GENERATOR, data[1]); + } + catch (Exception x) + { + if (x instanceof AuthenticationException) + throw (AuthenticationException) x; + throw new AuthenticationException("getConfiguration()", x); + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPClient.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPClient.java new file mode 100644 index 000000000..8e44e4ead --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPClient.java @@ -0,0 +1,954 @@ +/* SRPClient.java -- + Copyright (C) 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.crypto.sasl.srp; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.hash.MD5; +import gnu.java.security.util.PRNG; +import gnu.java.security.util.Util; +import gnu.javax.crypto.assembly.Direction; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.key.IKeyAgreementParty; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.KeyAgreementFactory; +import gnu.javax.crypto.key.OutgoingMessage; +import gnu.javax.crypto.key.srp6.SRP6KeyAgreement; +import gnu.javax.crypto.sasl.ClientMechanism; +import gnu.javax.crypto.sasl.IllegalMechanismStateException; +import gnu.javax.crypto.sasl.InputBuffer; +import gnu.javax.crypto.sasl.IntegrityException; +import gnu.javax.crypto.sasl.OutputBuffer; +import gnu.javax.security.auth.Password; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.StringTokenizer; +import java.util.logging.Logger; + +import javax.security.auth.DestroyFailedException; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.sasl.AuthenticationException; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslException; + +/** + * The SASL-SRP client-side mechanism. + */ +public class SRPClient + extends ClientMechanism + implements SaslClient +{ + private static final Logger log = Logger.getLogger(SRPClient.class.getName()); + private String uid; // the unique key for this type of client + private String U; // the authentication identity + BigInteger N, g, A, B; + private Password password; // the authentication credentials + private byte[] s; // the user's salt + private byte[] cIV, sIV; // client+server IVs, when confidentiality is on + private byte[] M1, M2; // client+server evidences + private byte[] cn, sn; // client's and server's nonce + private SRP srp; // SRP algorithm instance used by this client + private byte[] sid; // session ID when re-used + private int ttl; // session time-to-live in seconds + private byte[] sCB; // the peer's channel binding data + private String L; // available options + private String o; + private String chosenIntegrityAlgorithm; + private String chosenConfidentialityAlgorithm; + private int rawSendSize = Registry.SASL_BUFFER_MAX_LIMIT; + private byte[] K; // shared session key + private boolean replayDetection = true; // whether Replay Detection is on + private int inCounter = 0; // messages sequence numbers + private int outCounter = 0; + private IALG inMac, outMac; // if !null, use for integrity + private CALG inCipher, outCipher; // if !null, use for confidentiality + private IKeyAgreementParty clientHandler = + KeyAgreementFactory.getPartyAInstance(Registry.SRP_SASL_KA); + /** Our default source of randomness. */ + private PRNG prng = null; + + public SRPClient() + { + super(Registry.SASL_SRP_MECHANISM); + } + + protected void initMechanism() throws SaslException + { + // we shall keep track of the sid (and the security context of this SRP + // client) based on the initialisation parameters of an SRP session. + // we shall compute a unique key for those parameters and key the sid + // (and the security context) accordingly. + // 1. compute the mapping key. use MD5 (the fastest) for this purpose + final MD5 md = new MD5(); + byte[] b; + b = authorizationID.getBytes(); + md.update(b, 0, b.length); + b = serverName.getBytes(); + md.update(b, 0, b.length); + b = protocol.getBytes(); + md.update(b, 0, b.length); + if (channelBinding.length > 0) + md.update(channelBinding, 0, channelBinding.length); + + uid = Util.toBase64(md.digest()); + if (ClientStore.instance().isAlive(uid)) + { + final SecurityContext ctx = ClientStore.instance().restoreSession(uid); + srp = SRP.instance(ctx.getMdName()); + sid = ctx.getSID(); + K = ctx.getK(); + cIV = ctx.getClientIV(); + sIV = ctx.getServerIV(); + replayDetection = ctx.hasReplayDetection(); + inCounter = ctx.getInCounter(); + outCounter = ctx.getOutCounter(); + inMac = ctx.getInMac(); + outMac = ctx.getOutMac(); + inCipher = ctx.getInCipher(); + outCipher = ctx.getOutCipher(); + } + else + { + sid = new byte[0]; + ttl = 0; + K = null; + cIV = null; + sIV = null; + cn = null; + sn = null; + } + } + + protected void resetMechanism() throws SaslException + { + try + { + password.destroy(); + } + catch (DestroyFailedException dfe) + { + SaslException se = new SaslException("resetMechanism()"); + se.initCause(dfe); + throw se; + } + password = null; + M1 = null; + K = null; + cIV = null; + sIV = null; + inMac = outMac = null; + inCipher = outCipher = null; + sid = null; + ttl = 0; + cn = null; + sn = null; + } + + public boolean hasInitialResponse() + { + return true; + } + + public byte[] evaluateChallenge(final byte[] challenge) throws SaslException + { + switch (state) + { + case 0: + state++; + return sendIdentities(); + case 1: + state++; + final byte[] result = sendPublicKey(challenge); + try + { + password.destroy(); //don't need further this session + } + catch (DestroyFailedException x) + { + SaslException se = new SaslException("sendPublicKey()"); + se.initCause(se); + throw se; + } + return result; + case 2: // should only occur if session re-use was rejected + if (! complete) + { + state++; + return receiveEvidence(challenge); + } + // else fall through + default: + throw new IllegalMechanismStateException("evaluateChallenge()"); + } + } + + protected byte[] engineUnwrap(final byte[] incoming, final int offset, + final int len) throws SaslException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineUnwrap"); + if (inMac == null && inCipher == null) + throw new IllegalStateException("connection is not protected"); + // at this point one, or both, of confidentiality and integrity protection + // services are active. + final byte[] result; + try + { + if (inMac != null) + { // integrity bytes are at the end of the stream + final int macBytesCount = inMac.length(); + final int payloadLength = len - macBytesCount; + final byte[] received_mac = new byte[macBytesCount]; + System.arraycopy(incoming, offset + payloadLength, received_mac, 0, + macBytesCount); + if (Configuration.DEBUG) + log.fine("Got C (received MAC): " + Util.dumpString(received_mac)); + inMac.update(incoming, offset, payloadLength); + if (replayDetection) + { + inCounter++; + if (Configuration.DEBUG) + log.fine("inCounter=" + inCounter); + inMac.update(new byte[] { + (byte)(inCounter >>> 24), + (byte)(inCounter >>> 16), + (byte)(inCounter >>> 8), + (byte) inCounter }); + } + final byte[] computed_mac = inMac.doFinal(); + if (Configuration.DEBUG) + log.fine("Computed MAC: " + Util.dumpString(computed_mac)); + if (! Arrays.equals(received_mac, computed_mac)) + throw new IntegrityException("engineUnwrap()"); + // deal with the payload, which can be either plain or encrypted + if (inCipher != null) + result = inCipher.doFinal(incoming, offset, payloadLength); + else + { + result = new byte[len - macBytesCount]; + System.arraycopy(incoming, offset, result, 0, result.length); + } + } + else // no integrity protection; just confidentiality + result = inCipher.doFinal(incoming, offset, len); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new SaslException("engineUnwrap()", x); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineUnwrap"); + return result; + } + + protected byte[] engineWrap(final byte[] outgoing, final int offset, + final int len) throws SaslException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineWrap"); + if (outMac == null && outCipher == null) + throw new IllegalStateException("connection is not protected"); + // at this point one, or both, of confidentiality and integrity protection + // services are active. + byte[] result; + try + { + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + // Process the data + if (outCipher != null) + { + result = outCipher.doFinal(outgoing, offset, len); + if (Configuration.DEBUG) + log.fine("Encoding c (encrypted plaintext): " + + Util.dumpString(result)); + out.write(result); + if (outMac != null) + { + outMac.update(result); + if (replayDetection) + { + outCounter++; + if (Configuration.DEBUG) + log.fine("outCounter=" + outCounter); + outMac.update(new byte[] { + (byte)(outCounter >>> 24), + (byte)(outCounter >>> 16), + (byte)(outCounter >>> 8), + (byte) outCounter }); + } + final byte[] C = outMac.doFinal(); + out.write(C); + if (Configuration.DEBUG) + log.fine("Encoding C (integrity checksum): " + Util.dumpString(C)); + } + // else confidentiality only; do nothing + } + else // no confidentiality; just integrity [+ replay detection] + { + if (Configuration.DEBUG) + log.fine("Encoding p (plaintext): " + + Util.dumpString(outgoing, offset, len)); + out.write(outgoing, offset, len); + outMac.update(outgoing, offset, len); + if (replayDetection) + { + outCounter++; + if (Configuration.DEBUG) + log.fine("outCounter=" + outCounter); + outMac.update(new byte[] { + (byte)(outCounter >>> 24), + (byte)(outCounter >>> 16), + (byte)(outCounter >>> 8), + (byte) outCounter }); + } + final byte[] C = outMac.doFinal(); + out.write(C); + if (Configuration.DEBUG) + log.fine("Encoding C (integrity checksum): " + Util.dumpString(C)); + } + result = out.toByteArray(); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new SaslException("engineWrap()", x); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineWrap"); + return result; + } + + protected String getNegotiatedQOP() + { + if (inMac != null) + { + if (inCipher != null) + return Registry.QOP_AUTH_CONF; + return Registry.QOP_AUTH_INT; + } + return Registry.QOP_AUTH; + } + + protected String getNegotiatedStrength() + { + if (inMac != null) + { + if (inCipher != null) + return Registry.STRENGTH_HIGH; + return Registry.STRENGTH_MEDIUM; + } + return Registry.STRENGTH_LOW; + } + + protected String getNegotiatedRawSendSize() + { + return String.valueOf(rawSendSize); + } + + protected String getReuse() + { + return Registry.REUSE_TRUE; + } + + private byte[] sendIdentities() throws SaslException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "sendIdentities"); + // If necessary, prompt the client for the username and password + getUsernameAndPassword(); + if (Configuration.DEBUG) + { + log.fine("Password: \"" + new String(password.getPassword()) + "\""); + log.fine("Encoding U (username): \"" + U + "\""); + log.fine("Encoding I (userid): \"" + authorizationID + "\""); + } + // if session re-use generate new 16-byte nonce + if (sid.length != 0) + { + cn = new byte[16]; + getDefaultPRNG().nextBytes(cn); + } + else + cn = new byte[0]; + final OutputBuffer frameOut = new OutputBuffer(); + try + { + frameOut.setText(U); + frameOut.setText(authorizationID); + frameOut.setEOS(sid); // session ID to re-use + frameOut.setOS(cn); // client nonce + frameOut.setEOS(channelBinding); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new AuthenticationException("sendIdentities()", x); + } + final byte[] result = frameOut.encode(); + if (Configuration.DEBUG) + { + log.fine("C: " + Util.dumpString(result)); + log.fine(" U = " + U); + log.fine(" I = " + authorizationID); + log.fine("sid = " + new String(sid)); + log.fine(" cn = " + Util.dumpString(cn)); + log.fine("cCB = " + Util.dumpString(channelBinding)); + log.exiting(this.getClass().getName(), "sendIdentities"); + } + return result; + } + + private byte[] sendPublicKey(final byte[] input) throws SaslException + { + if (Configuration.DEBUG) + { + log.entering(this.getClass().getName(), "sendPublicKey"); + log.fine("S: " + Util.dumpString(input)); + } + // Server sends [00], N, g, s, B, L + // or [FF], sn, sCB + final InputBuffer frameIn = new InputBuffer(input); + final int ack; + try + { + ack = (int) frameIn.getScalar(1); + if (ack == 0x00) // new session + { + N = frameIn.getMPI(); + if (Configuration.DEBUG) + log.fine("Got N (modulus): " + Util.dump(N)); + g = frameIn.getMPI(); + if (Configuration.DEBUG) + log.fine("Got g (generator): " + Util.dump(g)); + s = frameIn.getOS(); + if (Configuration.DEBUG) + log.fine("Got s (salt): " + Util.dumpString(s)); + B = frameIn.getMPI(); + if (Configuration.DEBUG) + log.fine("Got B (server ephermeral public key): " + Util.dump(B)); + L = frameIn.getText(); + if (Configuration.DEBUG) + log.fine("Got L (available options): \"" + L + "\""); + } + else if (ack == 0xFF) // session re-use + { + sn = frameIn.getOS(); + if (Configuration.DEBUG) + log.fine("Got sn (server nonce): " + Util.dumpString(sn)); + sCB = frameIn.getEOS(); + if (Configuration.DEBUG) + log.fine("Got sCB (server channel binding): " + Util.dumpString(sCB)); + } + else // unexpected scalar + throw new SaslException("sendPublicKey(): Invalid scalar (" + ack + + ") in server's request"); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new SaslException("sendPublicKey()", x); + } + if (ack == 0x00) + { // new session --------------------------------------- + o = createO(L.toLowerCase()); // do this first to initialise the SRP hash + final byte[] pBytes; // use ASCII encoding to inter-operate w/ non-java + pBytes = password.getBytes(); + // ---------------------------------------------------------------------- + final HashMap mapA = new HashMap(); + mapA.put(SRP6KeyAgreement.HASH_FUNCTION, srp.getAlgorithm()); + mapA.put(SRP6KeyAgreement.USER_IDENTITY, U); + mapA.put(SRP6KeyAgreement.USER_PASSWORD, pBytes); + try + { + clientHandler.init(mapA); + clientHandler.processMessage(null); + } + catch (KeyAgreementException x) + { + throw new SaslException("sendPublicKey()", x); + } + // ------------------------------------------------------------------- + try + { + OutgoingMessage out = new OutgoingMessage(); + out.writeMPI(N); + out.writeMPI(g); + out.writeMPI(new BigInteger(1, s)); + out.writeMPI(B); + IncomingMessage in = new IncomingMessage(out.toByteArray()); + out = clientHandler.processMessage(in); + in = new IncomingMessage(out.toByteArray()); + A = in.readMPI(); + K = clientHandler.getSharedSecret(); + } + catch (KeyAgreementException x) + { + throw new SaslException("sendPublicKey()", x); + } + // ------------------------------------------------------------------- + if (Configuration.DEBUG) + { + log.fine("K: " + Util.dumpString(K)); + log.fine("Encoding A (client ephemeral public key): " + Util.dump(A)); + } + try + { + M1 = srp.generateM1(N, g, U, s, A, B, K, authorizationID, L, cn, + channelBinding); + } + catch (UnsupportedEncodingException x) + { + throw new AuthenticationException("sendPublicKey()", x); + } + if (Configuration.DEBUG) + { + log.fine("Encoding o (client chosen options): \"" + o + "\""); + log.fine("Encoding cIV (client IV): \"" + Util.dumpString(cIV) + "\""); + } + final OutputBuffer frameOut = new OutputBuffer(); + try + { + frameOut.setMPI(A); + frameOut.setOS(M1); + frameOut.setText(o); + frameOut.setOS(cIV); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new AuthenticationException("sendPublicKey()", x); + } + final byte[] result = frameOut.encode(); + if (Configuration.DEBUG) + { + log.fine("New session, or session re-use rejected..."); + log.fine("C: " + Util.dumpString(result)); + log.fine(" A = 0x" + A.toString(16)); + log.fine(" M1 = " + Util.dumpString(M1)); + log.fine(" o = " + o); + log.fine("cIV = " + Util.dumpString(cIV)); + log.exiting(this.getClass().getName(), "sendPublicKey"); + } + return result; + } + else // session re-use accepted ------------------------------------------- + { + setupSecurityServices(true); + if (Configuration.DEBUG) + { + log.fine("Session re-use accepted..."); + log.exiting(this.getClass().getName(), "sendPublicKey"); + } + return null; + } + } + + private byte[] receiveEvidence(byte[] input) throws SaslException + { + if (Configuration.DEBUG) + { + log.entering(this.getClass().getName(), "receiveEvidence"); + log.fine("S: " + Util.dumpString(input)); + } + // Server send M2, sIV, sCB, sid, ttl + final InputBuffer frameIn = new InputBuffer(input); + try + { + M2 = frameIn.getOS(); + if (Configuration.DEBUG) + log.fine("Got M2 (server evidence): " + Util.dumpString(M2)); + sIV = frameIn.getOS(); + if (Configuration.DEBUG) + log.fine("Got sIV (server IV): " + Util.dumpString(sIV)); + sid = frameIn.getEOS(); + if (Configuration.DEBUG) + log.fine("Got sid (session ID): " + new String(sid)); + ttl = (int) frameIn.getScalar(4); + if (Configuration.DEBUG) + log.fine("Got ttl (session time-to-live): " + ttl + "sec."); + sCB = frameIn.getEOS(); + if (Configuration.DEBUG) + log.fine("Got sCB (server channel binding): " + Util.dumpString(sCB)); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new AuthenticationException("receiveEvidence()", x); + } + + final byte[] expected; + try + { + expected = srp.generateM2(A, M1, K, U, authorizationID, o, sid, ttl, + cIV, sIV, sCB); + } + catch (UnsupportedEncodingException x) + { + throw new AuthenticationException("receiveEvidence()", x); + } + if (Configuration.DEBUG) + log.fine("Expected: " + Util.dumpString(expected)); + if (! Arrays.equals(M2, expected)) + throw new AuthenticationException("M2 mismatch"); + setupSecurityServices(false); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "receiveEvidence"); + return null; + } + + private void getUsernameAndPassword() throws AuthenticationException + { + try + { + if ((! properties.containsKey(Registry.SASL_USERNAME)) + && (! properties.containsKey(Registry.SASL_PASSWORD))) + { + final NameCallback nameCB; + final String defaultName = System.getProperty("user.name"); + if (defaultName == null) + nameCB = new NameCallback("username: "); + else + nameCB = new NameCallback("username: ", defaultName); + final PasswordCallback pwdCB = new PasswordCallback("password: ", + false); + handler.handle(new Callback[] { nameCB, pwdCB }); + U = nameCB.getName(); + password = new Password(pwdCB.getPassword()); + } + else + { + if (properties.containsKey(Registry.SASL_USERNAME)) + this.U = (String) properties.get(Registry.SASL_USERNAME); + else + { + final NameCallback nameCB; + final String defaultName = System.getProperty("user.name"); + if (defaultName == null) + nameCB = new NameCallback("username: "); + else + nameCB = new NameCallback("username: ", defaultName); + this.handler.handle(new Callback[] { nameCB }); + this.U = nameCB.getName(); + } + + if (properties.containsKey(Registry.SASL_PASSWORD)) + { + Object pw = properties.get(Registry.SASL_PASSWORD); + if (pw instanceof char[]) + password = new Password((char[]) pw); + else if (pw instanceof Password) + password = (Password) pw; + else if (pw instanceof String) + password = new Password(((String) pw).toCharArray()); + else + throw new IllegalArgumentException(pw.getClass().getName() + + "is not a valid password class"); + } + else + { + final PasswordCallback pwdCB = new PasswordCallback("password: ", + false); + this.handler.handle(new Callback[] { pwdCB }); + password = new Password(pwdCB.getPassword()); + } + } + + if (U == null) + throw new AuthenticationException("null username supplied"); + if (password == null) + throw new AuthenticationException("null password supplied"); + } + catch (UnsupportedCallbackException x) + { + throw new AuthenticationException("getUsernameAndPassword()", x); + } + catch (IOException x) + { + throw new AuthenticationException("getUsernameAndPassword()", x); + } + } + + // We go through the list of available services and for each available one + // we decide whether or not we want it enabled, based on properties passed + // to us by the client. + private String createO(final String aol) throws AuthenticationException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "createO", aol); + boolean replaydetectionAvailable = false; + boolean integrityAvailable = false; + boolean confidentialityAvailable = false; + String option, mandatory = SRPRegistry.DEFAULT_MANDATORY; + int i; + + String mdName = SRPRegistry.SRP_DEFAULT_DIGEST_NAME; + final StringTokenizer st = new StringTokenizer(aol, ","); + while (st.hasMoreTokens()) + { + option = st.nextToken(); + if (option.startsWith(SRPRegistry.OPTION_SRP_DIGEST + "=")) + { + option = option.substring(option.indexOf('=') + 1); + if (Configuration.DEBUG) + log.fine("mda: <" + option + ">"); + for (i = 0; i < SRPRegistry.INTEGRITY_ALGORITHMS.length; i++) + if (SRPRegistry.SRP_ALGORITHMS[i].equals(option)) + { + mdName = option; + break; + } + } + else if (option.equals(SRPRegistry.OPTION_REPLAY_DETECTION)) + replaydetectionAvailable = true; + else if (option.startsWith(SRPRegistry.OPTION_INTEGRITY + "=")) + { + option = option.substring(option.indexOf('=') + 1); + if (Configuration.DEBUG) + log.fine("ialg: <" + option + ">"); + for (i = 0; i < SRPRegistry.INTEGRITY_ALGORITHMS.length; i++) + if (SRPRegistry.INTEGRITY_ALGORITHMS[i].equals(option)) + { + chosenIntegrityAlgorithm = option; + integrityAvailable = true; + break; + } + } + else if (option.startsWith(SRPRegistry.OPTION_CONFIDENTIALITY + "=")) + { + option = option.substring(option.indexOf('=') + 1); + if (Configuration.DEBUG) + log.fine("calg: <" + option + ">"); + for (i = 0; i < SRPRegistry.CONFIDENTIALITY_ALGORITHMS.length; i++) + if (SRPRegistry.CONFIDENTIALITY_ALGORITHMS[i].equals(option)) + { + chosenConfidentialityAlgorithm = option; + confidentialityAvailable = true; + break; + } + } + else if (option.startsWith(SRPRegistry.OPTION_MANDATORY + "=")) + mandatory = option.substring(option.indexOf('=') + 1); + else if (option.startsWith(SRPRegistry.OPTION_MAX_BUFFER_SIZE + "=")) + { + final String maxBufferSize = option.substring(option.indexOf('=') + 1); + try + { + rawSendSize = Integer.parseInt(maxBufferSize); + if (rawSendSize > Registry.SASL_BUFFER_MAX_LIMIT + || rawSendSize < 1) + throw new AuthenticationException( + "Illegal value for 'maxbuffersize' option"); + } + catch (NumberFormatException x) + { + throw new AuthenticationException( + SRPRegistry.OPTION_MAX_BUFFER_SIZE + "=" + maxBufferSize, x); + } + } + } + String s; + Boolean flag; + s = (String) properties.get(SRPRegistry.SRP_REPLAY_DETECTION); + flag = Boolean.valueOf(s); + replayDetection = replaydetectionAvailable && flag.booleanValue(); + s = (String) properties.get(SRPRegistry.SRP_INTEGRITY_PROTECTION); + flag = Boolean.valueOf(s); + boolean integrity = integrityAvailable && flag.booleanValue(); + s = (String) properties.get(SRPRegistry.SRP_CONFIDENTIALITY); + flag = Boolean.valueOf(s); + boolean confidentiality = confidentialityAvailable && flag.booleanValue(); + // make sure we do the right thing + if (SRPRegistry.OPTION_REPLAY_DETECTION.equals(mandatory)) + { + replayDetection = true; + integrity = true; + } + else if (SRPRegistry.OPTION_INTEGRITY.equals(mandatory)) + integrity = true; + else if (SRPRegistry.OPTION_CONFIDENTIALITY.equals(mandatory)) + confidentiality = true; + + if (replayDetection) + { + if (chosenIntegrityAlgorithm == null) + throw new AuthenticationException( + "Replay detection is required but no integrity protection " + + "algorithm was chosen"); + } + if (integrity) + { + if (chosenIntegrityAlgorithm == null) + throw new AuthenticationException( + "Integrity protection is required but no algorithm was chosen"); + } + if (confidentiality) + { + if (chosenConfidentialityAlgorithm == null) + throw new AuthenticationException( + "Confidentiality protection is required but no algorithm was chosen"); + } + // 1. check if we'll be using confidentiality; if not set IV to 0-byte + if (chosenConfidentialityAlgorithm == null) + cIV = new byte[0]; + else + { + // 2. get the block size of the cipher + final IBlockCipher cipher = CipherFactory.getInstance(chosenConfidentialityAlgorithm); + if (cipher == null) + throw new AuthenticationException("createO()", + new NoSuchAlgorithmException()); + final int blockSize = cipher.defaultBlockSize(); + // 3. generate random iv + cIV = new byte[blockSize]; + getDefaultPRNG().nextBytes(cIV); + } + srp = SRP.instance(mdName); + // Now create the options list specifying which of the available options + // we have chosen. + + // For now we just select the defaults. Later we need to add support for + // properties (perhaps in a file) where a user can specify the list of + // algorithms they would prefer to use. + final CPStringBuilder sb = new CPStringBuilder(); + sb.append(SRPRegistry.OPTION_SRP_DIGEST) + .append("=").append(mdName).append(","); + if (replayDetection) + sb.append(SRPRegistry.OPTION_REPLAY_DETECTION).append(","); + if (integrity) + sb.append(SRPRegistry.OPTION_INTEGRITY) + .append("=").append(chosenIntegrityAlgorithm).append(","); + if (confidentiality) + sb.append(SRPRegistry.OPTION_CONFIDENTIALITY) + .append("=").append(chosenConfidentialityAlgorithm).append(","); + + final String result = sb.append(SRPRegistry.OPTION_MAX_BUFFER_SIZE) + .append("=").append(Registry.SASL_BUFFER_MAX_LIMIT) + .toString(); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "createO", result); + return result; + } + + private void setupSecurityServices(final boolean sessionReUse) + throws SaslException + { + complete = true; // signal end of authentication phase + if (! sessionReUse) + { + outCounter = inCounter = 0; + // instantiate cipher if confidentiality protection filter is active + if (chosenConfidentialityAlgorithm != null) + { + if (Configuration.DEBUG) + log.fine("Activating confidentiality protection filter"); + inCipher = CALG.getInstance(chosenConfidentialityAlgorithm); + outCipher = CALG.getInstance(chosenConfidentialityAlgorithm); + } + // instantiate hmacs if integrity protection filter is active + if (chosenIntegrityAlgorithm != null) + { + if (Configuration.DEBUG) + log.fine("Activating integrity protection filter"); + inMac = IALG.getInstance(chosenIntegrityAlgorithm); + outMac = IALG.getInstance(chosenIntegrityAlgorithm); + } + } + else // same session new Keys + K = srp.generateKn(K, cn, sn); + + final KDF kdf = KDF.getInstance(K); + // initialise in/out ciphers if confidentiality protection is used + if (inCipher != null) + { + inCipher.init(kdf, sIV, Direction.REVERSED); + outCipher.init(kdf, cIV, Direction.FORWARD); + } + // initialise in/out macs if integrity protection is used + if (inMac != null) + { + inMac.init(kdf); + outMac.init(kdf); + } + if (sid != null && sid.length != 0) + { // update the security context and save in map + if (Configuration.DEBUG) + log.fine("Updating security context for UID = " + uid); + ClientStore.instance().cacheSession(uid, + ttl, + new SecurityContext(srp.getAlgorithm(), + sid, + K, + cIV, + sIV, + replayDetection, + inCounter, + outCounter, + inMac, outMac, + inCipher, + outCipher)); + } + } + + private PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + return prng; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPRegistry.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPRegistry.java new file mode 100644 index 000000000..b6d24cf14 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPRegistry.java @@ -0,0 +1,165 @@ +/* SRPRegistry.java -- + Copyright (C) 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.crypto.sasl.srp; + +import gnu.java.security.Registry; + +/** + * A list of key names designating the values exchanged between the server + * and client in an SRP communication authentication phase. + */ +public interface SRPRegistry +{ + /** Indices of (N, g) parameter values for SRP (.conf) password database. */ + String N_2048_BITS = "1"; + String N_1536_BITS = "2"; + String N_1280_BITS = "3"; + String N_1024_BITS = "4"; + String N_768_BITS = "5"; + String N_640_BITS = "6"; + String N_512_BITS = "7"; + /** Available hash algorithms for all SRP calculations. */ + String[] SRP_ALGORITHMS = { + Registry.SHA160_HASH, // the default one + Registry.MD5_HASH, + Registry.RIPEMD128_HASH, + Registry.RIPEMD160_HASH, + + Registry.SHA256_HASH, + Registry.SHA384_HASH, + Registry.SHA512_HASH }; + /** + * The name of the default message digest algorithm to use when no name is + * explicitely given. In this implementation it is the first among + * those supported; i.e. the algorithm at index position #0: SHA with + * 160-bit output. + */ + String SRP_DEFAULT_DIGEST_NAME = SRP_ALGORITHMS[0]; + /** + * The property name of the message digest algorithm name to use in a given + * SRP incarnation. + */ + String SRP_DIGEST_NAME = "srp.digest.name"; + /** The public shared modulus: n. */ + String SHARED_MODULUS = "srp.N"; + /** The GF generator used: g. */ + String FIELD_GENERATOR = "srp.g"; + /** The list of server's available security options. */ + String AVAILABLE_OPTIONS = "srp.L"; + /** The client's chosen security options. */ + String CHOSEN_OPTIONS = "srp.o"; + /** The client's username. */ + String USER_NAME = "srp.U"; + /** The client's authorization ID. */ + String USER_ROLE = "srp.I"; + /** The user's salt. */ + String USER_SALT = "srp.s"; + /** The user's password verifier. */ + String PASSWORD_VERIFIER = "srp.v"; + /** The client's public ephemeral exponent: A. */ + String CLIENT_PUBLIC_KEY = "srp.A"; + /** The server's public ephemeral exponent: B. */ + String SERVER_PUBLIC_KEY = "srp.B"; + /** The client's evidence: M1. */ + String CLIENT_EVIDENCE = "srp.M1"; + /** The server's evidence: M2. */ + String SERVER_EVIDENCE = "srp.M2"; + /** Name of underlying hash algorithm for use with all SRP calculations. */ + String SRP_HASH = "gnu.crypto.sasl.srp.hash"; + /** Name of SRP mandatory service property. */ + String SRP_MANDATORY = "gnu.crypto.sasl.srp.mandatory"; + /** Name of SRP replay detection property. */ + String SRP_REPLAY_DETECTION = "gnu.crypto.sasl.srp.replay.detection"; + /** Name of SRP integrity protection property. */ + String SRP_INTEGRITY_PROTECTION = "gnu.crypto.sasl.srp.integrity"; + /** Name of SRP confidentiality protection property. */ + String SRP_CONFIDENTIALITY = "gnu.crypto.sasl.srp.confidentiality"; + /** Name of the main SRP password file pathname property. */ + String PASSWORD_FILE = "gnu.crypto.sasl.srp.password.file"; + /** + * Name of the SRP password database property --a reference to + * {@link PasswordFile} object. + */ + String PASSWORD_DB = "gnu.crypto.sasl.srp.password.db"; + /** Default fully qualified pathname of the SRP password file. */ + String DEFAULT_PASSWORD_FILE = "/etc/tpasswd"; + /** Default value for replay detection security service. */ + boolean DEFAULT_REPLAY_DETECTION = true; + /** Default value for integrity protection security service. */ + boolean DEFAULT_INTEGRITY = true; // implied by the previous option + /** Default value for confidentiality protection security service. */ + boolean DEFAULT_CONFIDENTIALITY = false; + // constants defining HMAC names + String HMAC_SHA1 = "hmac-sha1"; + String HMAC_MD5 = "hmac-md5"; + String HMAC_RIPEMD_160 = "hmac-ripemd-160"; + /** Available HMAC algorithms for integrity protection. */ + String[] INTEGRITY_ALGORITHMS = { HMAC_SHA1, HMAC_MD5, HMAC_RIPEMD_160 }; + // constants defining Cipher names + String AES = "aes"; + String BLOWFISH = "blowfish"; + /** Available Cipher algorithms for confidentiality protection. */ + String[] CONFIDENTIALITY_ALGORITHMS = { AES, BLOWFISH }; + /** String for mandatory replay detection. */ + String OPTION_MANDATORY = "mandatory"; + /** String for mda: the SRP digest algorithm name. */ + String OPTION_SRP_DIGEST = "mda"; + /** String for mandatory replay detection. */ + String OPTION_REPLAY_DETECTION = "replay_detection"; + /** String for mandatory integrity protection. */ + String OPTION_INTEGRITY = "integrity"; + /** String for mandatory confidentiality protection. */ + String OPTION_CONFIDENTIALITY = "confidentiality"; + /** String for mandatory replay detection. */ + String OPTION_MAX_BUFFER_SIZE = "maxbuffersize"; + /** String for no mandatory security service. */ + String MANDATORY_NONE = "none"; + /** Default mandatory security service required. */ + String DEFAULT_MANDATORY = OPTION_REPLAY_DETECTION; + /** Name of the UID field in the plain password file. */ + String MD_NAME_FIELD = "srp.md.name"; + /** Name of the GID field in the plain password file. */ + String USER_VERIFIER_FIELD = "srp.user.verifier"; + /** Name of the GECOS field in the plain password file. */ + String SALT_FIELD = "srp.salt"; + /** Name of the SHELL field in the plain password file. */ + String CONFIG_NDX_FIELD = "srp.config.ndx"; + /** Minimum bitlength of the SRP public modulus. */ + int MINIMUM_MODULUS_BITLENGTH = 512; +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPServer.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPServer.java new file mode 100644 index 000000000..fca5c3bf3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPServer.java @@ -0,0 +1,842 @@ +/* SRPServer.java -- + Copyright (C) 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.crypto.sasl.srp; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.util.PRNG; +import gnu.java.security.util.Util; +import gnu.javax.crypto.assembly.Direction; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.key.IKeyAgreementParty; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.KeyAgreementFactory; +import gnu.javax.crypto.key.OutgoingMessage; +import gnu.javax.crypto.key.srp6.SRP6KeyAgreement; +import gnu.javax.crypto.sasl.IllegalMechanismStateException; +import gnu.javax.crypto.sasl.InputBuffer; +import gnu.javax.crypto.sasl.IntegrityException; +import gnu.javax.crypto.sasl.OutputBuffer; +import gnu.javax.crypto.sasl.ServerMechanism; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.util.Arrays; +import java.util.HashMap; +import java.util.StringTokenizer; +import java.util.logging.Logger; + +import javax.security.sasl.AuthenticationException; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +/** + * The SASL-SRP server-side mechanism. + */ +public class SRPServer + extends ServerMechanism + implements SaslServer +{ + private static final Logger log = Logger.getLogger(SRPServer.class.getName()); + private String U = null; // client's username + private BigInteger N, g, A, B; + private byte[] s; // salt + private byte[] cIV, sIV; // client+server IVs, when confidentiality is on + private byte[] cn, sn; // client's and server's nonce + private SRP srp; // SRP algorithm instance used by this server + private byte[] sid; // session ID when re-used + private int ttl = 360; // session time-to-live in seconds + private byte[] cCB; // peer's channel binding' + private String mandatory; // List of available options + private String L = null; + private String o; + private String chosenIntegrityAlgorithm; + private String chosenConfidentialityAlgorithm; + private int rawSendSize = Registry.SASL_BUFFER_MAX_LIMIT; + private byte[] K; // shared session key + private boolean replayDetection = true; // whether Replay Detection is on + private int inCounter = 0; // messages sequence numbers + private int outCounter = 0; + private IALG inMac, outMac; // if !null, use for integrity + private CALG inCipher, outCipher; // if !null, use for confidentiality + private IKeyAgreementParty serverHandler = + KeyAgreementFactory.getPartyBInstance(Registry.SRP_SASL_KA); + /** Our default source of randomness. */ + private PRNG prng = null; + + public SRPServer() + { + super(Registry.SASL_SRP_MECHANISM); + } + + protected void initMechanism() throws SaslException + { + // TODO: + // we must have a means to map a given username to a preferred + // SRP hash algorithm; otherwise we end up using _always_ SHA. + // for the time being get it from the mechanism properties map + // and apply it for all users. + final String mda = (String) properties.get(SRPRegistry.SRP_HASH); + srp = SRP.instance(mda == null ? SRPRegistry.SRP_DEFAULT_DIGEST_NAME : mda); + } + + protected void resetMechanism() throws SaslException + { + s = null; + A = B = null; + K = null; + inMac = outMac = null; + inCipher = outCipher = null; + sid = null; + } + + public byte[] evaluateResponse(final byte[] response) throws SaslException + { + switch (state) + { + case 0: + if (response == null) + return null; + state++; + return sendProtocolElements(response); + case 1: + if (! complete) + { + state++; + return sendEvidence(response); + } + // else fall through + default: + throw new IllegalMechanismStateException("evaluateResponse()"); + } + } + + protected byte[] engineUnwrap(final byte[] incoming, final int offset, + final int len) throws SaslException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineUnwrap"); + if (inMac == null && inCipher == null) + throw new IllegalStateException("connection is not protected"); + if (Configuration.DEBUG) + log.fine("Incoming buffer (before security): " + + Util.dumpString(incoming, offset, len)); + // at this point one, or both, of confidentiality and integrity protection + // services are active. + final byte[] result; + try + { + if (inMac != null) + { // integrity bytes are at the end of the stream + final int macBytesCount = inMac.length(); + final int payloadLength = len - macBytesCount; + final byte[] received_mac = new byte[macBytesCount]; + System.arraycopy(incoming, offset + payloadLength, received_mac, 0, + macBytesCount); + if (Configuration.DEBUG) + log.fine("Got C (received MAC): " + Util.dumpString(received_mac)); + inMac.update(incoming, offset, payloadLength); + if (replayDetection) + { + inCounter++; + if (Configuration.DEBUG) + log.fine("inCounter=" + String.valueOf(inCounter)); + inMac.update(new byte[] { + (byte)(inCounter >>> 24), + (byte)(inCounter >>> 16), + (byte)(inCounter >>> 8), + (byte) inCounter }); + } + final byte[] computed_mac = inMac.doFinal(); + if (Configuration.DEBUG) + log.fine("Computed MAC: " + Util.dumpString(computed_mac)); + if (! Arrays.equals(received_mac, computed_mac)) + throw new IntegrityException("engineUnwrap()"); + // deal with the payload, which can be either plain or encrypted + if (inCipher != null) + result = inCipher.doFinal(incoming, offset, payloadLength); + else + { + result = new byte[payloadLength]; + System.arraycopy(incoming, offset, result, 0, result.length); + } + } + else // no integrity protection; just confidentiality + result = inCipher.doFinal(incoming, offset, len); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new SaslException("engineUnwrap()", x); + } + if (Configuration.DEBUG) + { + log.fine("Incoming buffer (after security): " + Util.dumpString(result)); + log.exiting(this.getClass().getName(), "engineUnwrap"); + } + return result; + } + + protected byte[] engineWrap(final byte[] outgoing, final int offset, + final int len) throws SaslException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineWrap"); + if (outMac == null && outCipher == null) + throw new IllegalStateException("connection is not protected"); + if (Configuration.DEBUG) + { + log.fine("Outgoing buffer (before security) (hex): " + + Util.dumpString(outgoing, offset, len)); + log.fine("Outgoing buffer (before security) (str): \"" + + new String(outgoing, offset, len) + "\""); + } + // at this point one, or both, of confidentiality and integrity protection + // services are active. + byte[] result; + try + { + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + if (outCipher != null) + { + result = outCipher.doFinal(outgoing, offset, len); + if (Configuration.DEBUG) + log.fine("Encoding c (encrypted plaintext): " + + Util.dumpString(result)); + out.write(result); + if (outMac != null) + { + outMac.update(result); + if (replayDetection) + { + outCounter++; + if (Configuration.DEBUG) + log.fine("outCounter=" + outCounter); + outMac.update(new byte[] { + (byte)(outCounter >>> 24), + (byte)(outCounter >>> 16), + (byte)(outCounter >>> 8), + (byte) outCounter }); + } + final byte[] C = outMac.doFinal(); + out.write(C); + if (Configuration.DEBUG) + log.fine("Encoding C (integrity checksum): " + Util.dumpString(C)); + } + // else ciphertext only; do nothing + } + else // no confidentiality; just integrity [+ replay detection] + { + if (Configuration.DEBUG) + log.fine("Encoding p (plaintext): " + + Util.dumpString(outgoing, offset, len)); + out.write(outgoing, offset, len); + outMac.update(outgoing, offset, len); + if (replayDetection) + { + outCounter++; + if (Configuration.DEBUG) + log.fine("outCounter=" + outCounter); + outMac.update(new byte[] { + (byte)(outCounter >>> 24), + (byte)(outCounter >>> 16), + (byte)(outCounter >>> 8), + (byte) outCounter }); + } + final byte[] C = outMac.doFinal(); + out.write(C); + if (Configuration.DEBUG) + log.fine("Encoding C (integrity checksum): " + Util.dumpString(C)); + } + result = out.toByteArray(); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new SaslException("engineWrap()", x); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineWrap"); + return result; + } + + protected String getNegotiatedQOP() + { + if (inMac != null) + { + if (inCipher != null) + return Registry.QOP_AUTH_CONF; + return Registry.QOP_AUTH_INT; + } + return Registry.QOP_AUTH; + } + + protected String getNegotiatedStrength() + { + if (inMac != null) + { + if (inCipher != null) + return Registry.STRENGTH_HIGH; + return Registry.STRENGTH_MEDIUM; + } + return Registry.STRENGTH_LOW; + } + + protected String getNegotiatedRawSendSize() + { + return String.valueOf(rawSendSize); + } + + protected String getReuse() + { + return Registry.REUSE_TRUE; + } + + private byte[] sendProtocolElements(final byte[] input) throws SaslException + { + if (Configuration.DEBUG) + { + log.entering(this.getClass().getName(), "sendProtocolElements"); + log.fine("C: " + Util.dumpString(input)); + } + // Client send U, I, sid, cn + final InputBuffer frameIn = new InputBuffer(input); + try + { + U = frameIn.getText(); // Extract username + if (Configuration.DEBUG) + log.fine("Got U (username): \"" + U + "\""); + authorizationID = frameIn.getText(); // Extract authorisation ID + if (Configuration.DEBUG) + log.fine("Got I (userid): \"" + authorizationID + "\""); + sid = frameIn.getEOS(); + if (Configuration.DEBUG) + log.fine("Got sid (session ID): " + new String(sid)); + cn = frameIn.getOS(); + if (Configuration.DEBUG) + log.fine("Got cn (client nonce): " + Util.dumpString(cn)); + cCB = frameIn.getEOS(); + if (Configuration.DEBUG) + log.fine("Got cCB (client channel binding): " + Util.dumpString(cCB)); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new AuthenticationException("sendProtocolElements()", x); + } + // do/can we re-use? + if (ServerStore.instance().isAlive(sid)) + { + final SecurityContext ctx = ServerStore.instance().restoreSession(sid); + srp = SRP.instance(ctx.getMdName()); + K = ctx.getK(); + cIV = ctx.getClientIV(); + sIV = ctx.getServerIV(); + replayDetection = ctx.hasReplayDetection(); + inCounter = ctx.getInCounter(); + outCounter = ctx.getOutCounter(); + inMac = ctx.getInMac(); + outMac = ctx.getOutMac(); + inCipher = ctx.getInCipher(); + outCipher = ctx.getOutCipher(); + if (sn == null || sn.length != 16) + sn = new byte[16]; + getDefaultPRNG().nextBytes(sn); + setupSecurityServices(false); + final OutputBuffer frameOut = new OutputBuffer(); + try + { + frameOut.setScalar(1, 0xFF); + frameOut.setOS(sn); + frameOut.setEOS(channelBinding); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new AuthenticationException("sendProtocolElements()", x); + } + final byte[] result = frameOut.encode(); + if (Configuration.DEBUG) + { + log.fine("Old session..."); + log.fine("S: " + Util.dumpString(result)); + log.fine(" sn = " + Util.dumpString(sn)); + log.fine(" sCB = " + Util.dumpString(channelBinding)); + log.exiting(this.getClass().getName(), "sendProtocolElements"); + } + return result; + } + else + { // new session + authenticator.activate(properties); + // ------------------------------------------------------------------- + final HashMap mapB = new HashMap(); + mapB.put(SRP6KeyAgreement.HASH_FUNCTION, srp.getAlgorithm()); + mapB.put(SRP6KeyAgreement.HOST_PASSWORD_DB, authenticator); + try + { + serverHandler.init(mapB); + OutgoingMessage out = new OutgoingMessage(); + out.writeString(U); + IncomingMessage in = new IncomingMessage(out.toByteArray()); + out = serverHandler.processMessage(in); + in = new IncomingMessage(out.toByteArray()); + N = in.readMPI(); + g = in.readMPI(); + s = in.readMPI().toByteArray(); + B = in.readMPI(); + } + catch (KeyAgreementException x) + { + throw new SaslException("sendProtocolElements()", x); + } + // ------------------------------------------------------------------- + if (Configuration.DEBUG) + { + log.fine("Encoding N (modulus): " + Util.dump(N)); + log.fine("Encoding g (generator): " + Util.dump(g)); + log.fine("Encoding s (client's salt): " + Util.dumpString(s)); + log.fine("Encoding B (server ephemeral public key): " + Util.dump(B)); + } + // The server creates an options list (L), which consists of a + // comma-separated list of option strings that specify the security + // service options the server supports. + L = createL(); + if (Configuration.DEBUG) + { + log.fine("Encoding L (available options): \"" + L + "\""); + log.fine("Encoding sIV (server IV): " + Util.dumpString(sIV)); + } + final OutputBuffer frameOut = new OutputBuffer(); + try + { + frameOut.setScalar(1, 0x00); + frameOut.setMPI(N); + frameOut.setMPI(g); + frameOut.setOS(s); + frameOut.setMPI(B); + frameOut.setText(L); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new AuthenticationException("sendProtocolElements()", x); + } + final byte[] result = frameOut.encode(); + if (Configuration.DEBUG) + { + log.fine("New session..."); + log.fine("S: " + Util.dumpString(result)); + log.fine(" N = 0x" + N.toString(16)); + log.fine(" g = 0x" + g.toString(16)); + log.fine(" s = " + Util.dumpString(s)); + log.fine(" B = 0x" + B.toString(16)); + log.fine(" L = " + L); + log.exiting(this.getClass().getName(), "sendProtocolElements"); + } + return result; + } + } + + private byte[] sendEvidence(final byte[] input) throws SaslException + { + if (Configuration.DEBUG) + { + log.entering(this.getClass().getName(), "sendEvidence"); + log.fine("C: " + Util.dumpString(input)); + } + // Client send A, M1, o, cIV + final InputBuffer frameIn = new InputBuffer(input); + final byte[] M1; + try + { + A = frameIn.getMPI(); // Extract client's ephemeral public key + if (Configuration.DEBUG) + log.fine("Got A (client ephemeral public key): " + Util.dump(A)); + M1 = frameIn.getOS(); // Extract evidence + if (Configuration.DEBUG) + log.fine("Got M1 (client evidence): " + Util.dumpString(M1)); + o = frameIn.getText(); // Extract client's options list + if (Configuration.DEBUG) + log.fine("Got o (client chosen options): \"" + o + "\""); + cIV = frameIn.getOS(); // Extract client's IV + if (Configuration.DEBUG) + log.fine("Got cIV (client IV): " + Util.dumpString(cIV)); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new AuthenticationException("sendEvidence()", x); + } + // Parse client's options and set security layer variables + parseO(o); + // ---------------------------------------------------------------------- + try + { + final OutgoingMessage out = new OutgoingMessage(); + out.writeMPI(A); + final IncomingMessage in = new IncomingMessage(out.toByteArray()); + serverHandler.processMessage(in); + K = serverHandler.getSharedSecret(); + } + catch (KeyAgreementException x) + { + throw new SaslException("sendEvidence()", x); + } + // ---------------------------------------------------------------------- + if (Configuration.DEBUG) + log.fine("K: " + Util.dumpString(K)); + final byte[] expected; + try + { + expected = srp.generateM1(N, g, U, s, A, B, K, authorizationID, L, cn, + cCB); + } + catch (UnsupportedEncodingException x) + { + throw new AuthenticationException("sendEvidence()", x); + } + // Verify client evidence + if (! Arrays.equals(M1, expected)) + throw new AuthenticationException("M1 mismatch"); + setupSecurityServices(true); + final byte[] M2; + try + { + M2 = srp.generateM2(A, M1, K, U, authorizationID, o, sid, ttl, cIV, + sIV, channelBinding); + } + catch (UnsupportedEncodingException x) + { + throw new AuthenticationException("sendEvidence()", x); + } + final OutputBuffer frameOut = new OutputBuffer(); + try + { + frameOut.setOS(M2); + frameOut.setOS(sIV); + frameOut.setEOS(sid); + frameOut.setScalar(4, ttl); + frameOut.setEOS(channelBinding); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new AuthenticationException("sendEvidence()", x); + } + final byte[] result = frameOut.encode(); + if (Configuration.DEBUG) + { + log.fine("S: " + Util.dumpString(result)); + log.fine(" M2 = " + Util.dumpString(M2)); + log.fine(" sIV = " + Util.dumpString(sIV)); + log.fine(" sid = " + new String(sid)); + log.fine(" ttl = " + ttl); + log.fine(" sCB = " + Util.dumpString(channelBinding)); + log.exiting(this.getClass().getName(), "sendEvidence"); + } + return result; + } + + private String createL() + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "createL()"); + String s = (String) properties.get(SRPRegistry.SRP_MANDATORY); + if (s == null) + s = SRPRegistry.DEFAULT_MANDATORY; + + if (! SRPRegistry.MANDATORY_NONE.equals(s) + && ! SRPRegistry.OPTION_REPLAY_DETECTION.equals(s) + && ! SRPRegistry.OPTION_INTEGRITY.equals(s) + && ! SRPRegistry.OPTION_CONFIDENTIALITY.equals(s)) + { + if (Configuration.DEBUG) + log.fine("Unrecognised mandatory option (" + s + "). Using default..."); + s = SRPRegistry.DEFAULT_MANDATORY; + } + mandatory = s; + s = (String) properties.get(SRPRegistry.SRP_CONFIDENTIALITY); + final boolean confidentiality = (s == null ? SRPRegistry.DEFAULT_CONFIDENTIALITY + : Boolean.valueOf(s).booleanValue()); + s = (String) properties.get(SRPRegistry.SRP_INTEGRITY_PROTECTION); + boolean integrity = (s == null ? SRPRegistry.DEFAULT_INTEGRITY + : Boolean.valueOf(s).booleanValue()); + s = (String) properties.get(SRPRegistry.SRP_REPLAY_DETECTION); + final boolean replayDetection = (s == null ? SRPRegistry.DEFAULT_REPLAY_DETECTION + : Boolean.valueOf(s).booleanValue()); + final CPStringBuilder sb = new CPStringBuilder(); + sb.append(SRPRegistry.OPTION_SRP_DIGEST).append("=") + .append(srp.getAlgorithm()).append(","); + + if (! SRPRegistry.MANDATORY_NONE.equals(mandatory)) + sb.append(SRPRegistry.OPTION_MANDATORY) + .append("=").append(mandatory).append(","); + + if (replayDetection) + { + sb.append(SRPRegistry.OPTION_REPLAY_DETECTION).append(","); + // if replay detection is on then force integrity protection + integrity = true; + } + int i; + if (integrity) + { + for (i = 0; i < SRPRegistry.INTEGRITY_ALGORITHMS.length; i++) + sb.append(SRPRegistry.OPTION_INTEGRITY).append("=") + .append(SRPRegistry.INTEGRITY_ALGORITHMS[i]).append(","); + } + if (confidentiality) + { + IBlockCipher cipher; + for (i = 0; i < SRPRegistry.CONFIDENTIALITY_ALGORITHMS.length; i++) + { + cipher = CipherFactory.getInstance(SRPRegistry.CONFIDENTIALITY_ALGORITHMS[i]); + if (cipher != null) + sb.append(SRPRegistry.OPTION_CONFIDENTIALITY).append("=") + .append(SRPRegistry.CONFIDENTIALITY_ALGORITHMS[i]).append(","); + } + } + final String result = sb.append(SRPRegistry.OPTION_MAX_BUFFER_SIZE) + .append("=").append(Registry.SASL_BUFFER_MAX_LIMIT) + .toString(); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "createL"); + return result; + } + + // Parse client's options and set security layer variables + private void parseO(final String o) throws AuthenticationException + { + this.replayDetection = false; + boolean integrity = false; + boolean confidentiality = false; + String option; + int i; + + final StringTokenizer st = new StringTokenizer(o.toLowerCase(), ","); + while (st.hasMoreTokens()) + { + option = st.nextToken(); + if (Configuration.DEBUG) + log.fine("option: <" + option + ">"); + if (option.equals(SRPRegistry.OPTION_REPLAY_DETECTION)) + replayDetection = true; + else if (option.startsWith(SRPRegistry.OPTION_INTEGRITY + "=")) + { + if (integrity) + throw new AuthenticationException( + "Only one integrity algorithm may be chosen"); + option = option.substring(option.indexOf('=') + 1); + if (Configuration.DEBUG) + log.fine("algorithm: <" + option + ">"); + for (i = 0; i < SRPRegistry.INTEGRITY_ALGORITHMS.length; i++) + { + if (SRPRegistry.INTEGRITY_ALGORITHMS[i].equals(option)) + { + chosenIntegrityAlgorithm = option; + integrity = true; + break; + } + } + if (! integrity) + throw new AuthenticationException("Unknown integrity algorithm: " + + option); + } + else if (option.startsWith(SRPRegistry.OPTION_CONFIDENTIALITY + "=")) + { + if (confidentiality) + throw new AuthenticationException( + "Only one confidentiality algorithm may be chosen"); + option = option.substring(option.indexOf('=') + 1); + if (Configuration.DEBUG) + log.fine("algorithm: <" + option + ">"); + for (i = 0; i < SRPRegistry.CONFIDENTIALITY_ALGORITHMS.length; i++) + { + if (SRPRegistry.CONFIDENTIALITY_ALGORITHMS[i].equals(option)) + { + chosenConfidentialityAlgorithm = option; + confidentiality = true; + break; + } + } + if (! confidentiality) + throw new AuthenticationException("Unknown confidentiality algorithm: " + + option); + } + else if (option.startsWith(SRPRegistry.OPTION_MAX_BUFFER_SIZE + "=")) + { + final String maxBufferSize = option.substring(option.indexOf('=') + 1); + try + { + rawSendSize = Integer.parseInt(maxBufferSize); + if (rawSendSize > Registry.SASL_BUFFER_MAX_LIMIT + || rawSendSize < 1) + throw new AuthenticationException( + "Illegal value for 'maxbuffersize' option"); + } + catch (NumberFormatException x) + { + throw new AuthenticationException( + SRPRegistry.OPTION_MAX_BUFFER_SIZE + "=" + maxBufferSize, x); + } + } + } + // check if client did the right thing + if (replayDetection) + { + if (! integrity) + throw new AuthenticationException( + "Missing integrity protection algorithm but replay detection is chosen"); + } + if (mandatory.equals(SRPRegistry.OPTION_REPLAY_DETECTION)) + { + if (! replayDetection) + throw new AuthenticationException( + "Replay detection is mandatory but was not chosen"); + } + if (mandatory.equals(SRPRegistry.OPTION_INTEGRITY)) + { + if (! integrity) + throw new AuthenticationException( + "Integrity protection is mandatory but was not chosen"); + } + if (mandatory.equals(SRPRegistry.OPTION_CONFIDENTIALITY)) + { + if (! confidentiality) + throw new AuthenticationException( + "Confidentiality is mandatory but was not chosen"); + } + int blockSize = 0; + if (chosenConfidentialityAlgorithm != null) + { + final IBlockCipher cipher = CipherFactory.getInstance(chosenConfidentialityAlgorithm); + if (cipher != null) + blockSize = cipher.defaultBlockSize(); + else // should not happen + throw new AuthenticationException("Confidentiality algorithm (" + + chosenConfidentialityAlgorithm + + ") not available"); + } + sIV = new byte[blockSize]; + if (blockSize > 0) + getDefaultPRNG().nextBytes(sIV); + } + + private void setupSecurityServices(final boolean newSession) + throws SaslException + { + complete = true; // signal end of authentication phase + if (newSession) + { + outCounter = inCounter = 0; + // instantiate cipher if confidentiality protection filter is active + if (chosenConfidentialityAlgorithm != null) + { + if (Configuration.DEBUG) + log.fine("Activating confidentiality protection filter"); + inCipher = CALG.getInstance(chosenConfidentialityAlgorithm); + outCipher = CALG.getInstance(chosenConfidentialityAlgorithm); + } + // instantiate hmacs if integrity protection filter is active + if (chosenIntegrityAlgorithm != null) + { + if (Configuration.DEBUG) + log.fine("Activating integrity protection filter"); + inMac = IALG.getInstance(chosenIntegrityAlgorithm); + outMac = IALG.getInstance(chosenIntegrityAlgorithm); + } + // generate a new sid if at least integrity is used + sid = (inMac != null ? ServerStore.getNewSessionID() : new byte[0]); + } + else // same session new keys + K = srp.generateKn(K, cn, sn); + + final KDF kdf = KDF.getInstance(K); + // initialise in/out ciphers if confidentaility protection is used + if (inCipher != null) + { + outCipher.init(kdf, sIV, Direction.FORWARD); + inCipher.init(kdf, cIV, Direction.REVERSED); + } + // initialise in/out macs if integrity protection is used + if (inMac != null) + { + outMac.init(kdf); + inMac.init(kdf); + } + if (sid != null && sid.length != 0) + { // update the security context and save in map + if (Configuration.DEBUG) + log.fine("Updating security context for sid = " + new String(sid)); + ServerStore.instance().cacheSession(ttl, + new SecurityContext(srp.getAlgorithm(), + sid, + K, + cIV, + sIV, + replayDetection, + inCounter, + outCounter, + inMac, outMac, + inCipher, + outCipher)); + } + } + + private PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + return prng; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/SecurityContext.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/SecurityContext.java new file mode 100644 index 000000000..41ec57c81 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/SecurityContext.java @@ -0,0 +1,140 @@ +/* SecurityContext.java -- + Copyright (C) 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.crypto.sasl.srp; + +/** + * A package-private placeholder for an SRP security context. + */ +class SecurityContext +{ + private String mdName; + private byte[] sid; + private byte[] K; + private byte[] cIV; + private byte[] sIV; + private boolean replayDetection; + private int inCounter; + private int outCounter; + private IALG inMac; + private IALG outMac; + private CALG inCipher; + private CALG outCipher; + + SecurityContext(final String mdName, final byte[] sid, final byte[] K, + final byte[] cIV, final byte[] sIV, + final boolean replayDetection, final int inCounter, + final int outCounter, final IALG inMac, final IALG outMac, + final CALG inCipher, final CALG outCipher) + { + super(); + + this.mdName = mdName; + this.sid = sid; + this.K = K; + this.cIV = cIV; + this.sIV = sIV; + this.replayDetection = replayDetection; + this.inCounter = inCounter; + this.outCounter = outCounter; + this.inMac = inMac; + this.outMac = outMac; + this.inCipher = inCipher; + this.outCipher = outCipher; + } + + String getMdName() + { + return mdName; + } + + byte[] getSID() + { + return sid; + } + + byte[] getK() + { + return K; + } + + byte[] getClientIV() + { + return cIV; + } + + byte[] getServerIV() + { + return sIV; + } + + boolean hasReplayDetection() + { + return replayDetection; + } + + int getInCounter() + { + return inCounter; + } + + int getOutCounter() + { + return outCounter; + } + + IALG getInMac() + { + return inMac; + } + + IALG getOutMac() + { + return outMac; + } + + CALG getInCipher() + { + return inCipher; + } + + CALG getOutCipher() + { + return outCipher; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/ServerStore.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/ServerStore.java new file mode 100644 index 000000000..d98747324 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/ServerStore.java @@ -0,0 +1,177 @@ +/* ServerStore.java -- + Copyright (C) 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.crypto.sasl.srp; + +import gnu.java.lang.CPStringBuilder; + +import java.util.HashMap; + +/** + * The server-side implementation of the SRP security context store. + */ +public class ServerStore +{ + /** The underlying singleton. */ + private static ServerStore singleton = null; + /** The map of sid --> Security Context record. */ + private static final HashMap sid2ssc = new HashMap(); + /** The map of sid --> Session timing record. */ + private static final HashMap sid2ttl = new HashMap(); + /** A synchronisation lock. */ + private static final Object lock = new Object(); + /** A counter to generate legible SIDs. */ + private static int counter = 0; + + /** Private constructor to enforce Singleton pattern. */ + private ServerStore() + { + super(); + + // TODO: add a cleaning timer thread + } + + /** + * Returns the classloader Singleton. + * + * @return the classloader Singleton instance. + */ + static synchronized final ServerStore instance() + { + if (singleton == null) + singleton = new ServerStore(); + return singleton; + } + + /** + * Returns a legible new session identifier. + * + * @return a new session identifier. + */ + static synchronized final byte[] getNewSessionID() + { + final String sid = String.valueOf(++counter); + return new CPStringBuilder("SID-") + .append("0000000000".substring(0, 10 - sid.length())).append(sid) + .toString().getBytes(); + } + + /** + * Returns a boolean flag indicating if the designated session is still alive + * or not. + * + * @param sid the identifier of the session to check. + * @return true if the designated session is still alive. + * false otherwise. + */ + boolean isAlive(final byte[] sid) + { + boolean result = false; + if (sid != null && sid.length != 0) + { + synchronized (lock) + { + final String key = new String(sid); + final StoreEntry ctx = (StoreEntry) sid2ttl.get(key); + if (ctx != null) + { + result = ctx.isAlive(); + if (! result) // invalidate it en-passant + { + sid2ssc.remove(key); + sid2ttl.remove(key); + } + } + } + } + return result; + } + + /** + * Records a mapping between a session identifier and the Security Context of + * the designated SRP server mechanism instance. + * + * @param ttl the session's Time-To-Live indicator (in seconds). + * @param ctx the server's security context. + */ + void cacheSession(final int ttl, final SecurityContext ctx) + { + synchronized (lock) + { + final String key = new String(ctx.getSID()); + sid2ssc.put(key, ctx); + sid2ttl.put(key, new StoreEntry(ttl)); + } + } + + /** + * Updates the mapping between the designated session identifier and the + * designated server's SASL Security Context. In the process, computes and + * return the underlying mechanism server's evidence that shall be returned to + * the client in a session re-use exchange. + * + * @param sid the identifier of the session to restore. + * @return an SRP server's security context. + */ + SecurityContext restoreSession(final byte[] sid) + { + final String key = new String(sid); + final SecurityContext result; + synchronized (lock) + { + result = (SecurityContext) sid2ssc.remove(key); + sid2ttl.remove(key); + } + return result; + } + + /** + * Removes all information related to the designated session ID. + * + * @param sid the identifier of the seesion to invalidate. + */ + void invalidateSession(final byte[] sid) + { + final String key = new String(sid); + synchronized (lock) + { + sid2ssc.remove(key); + sid2ttl.remove(key); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/StoreEntry.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/StoreEntry.java new file mode 100644 index 000000000..ae64fa774 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/StoreEntry.java @@ -0,0 +1,75 @@ +/* StoreEntry.java -- + Copyright (C) 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.crypto.sasl.srp; + +/** + * A simple timing-related object for use by SRP re-use code. + */ +class StoreEntry +{ + private boolean perenial; + private long timeToDie; + + StoreEntry(int ttl) + { + super(); + + if (ttl == 0) + { + perenial = true; + timeToDie = 0L; + } + else + { + perenial = false; + timeToDie = System.currentTimeMillis() + (ttl & 0xFFFFFFFFL) * 1000L; + } + } + + /** + * Returns true if the Time-To_live period has not elapsed. + * + * @return true if the Time-To-Live period (in seconds) has not + * elapsed yet; false otherwise. + */ + boolean isAlive() + { + return (perenial ? true : (System.currentTimeMillis() < timeToDie)); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/IIOInputStream.java b/libjava/classpath/gnu/javax/imageio/IIOInputStream.java new file mode 100644 index 000000000..1ede75f78 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/IIOInputStream.java @@ -0,0 +1,102 @@ +/* GIFStream.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio; + +import java.io.InputStream; +import java.io.IOException; +import javax.imageio.stream.ImageInputStream; + +/** + * Implements InputStream on an ImageInputStream + * The purpose of this is to avoid IIO dependencies in the various decoders. + * (which only use read() anyway). + */ +public class IIOInputStream extends InputStream +{ + private ImageInputStream is; + + public IIOInputStream( ImageInputStream is ) + { + this.is = is; + } + + public int available() + { + return 0; + } + + public void close() throws IOException + { + is.close(); + } + + public void mark(int readlimit) + { + is.mark(); + } + + public boolean markSupported() + { + return true; + } + + public int read() throws IOException + { + return is.read(); + } + + public int read(byte[] b) throws IOException + { + return is.read(b); + } + + public int read(byte[] b, int offset, int length) throws IOException + { + return is.read(b, offset, length); + } + + public void reset() throws IOException + { + is.reset(); + } + + public long skip(long n) throws IOException + { + return is.skipBytes(n); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/bmp/BMPDecoder.java b/libjava/classpath/gnu/javax/imageio/bmp/BMPDecoder.java new file mode 100644 index 000000000..108461931 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/bmp/BMPDecoder.java @@ -0,0 +1,168 @@ +/* BMPDecoder.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.bmp; + +import java.io.IOException; +import javax.imageio.stream.ImageInputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.awt.image.IndexColorModel; +import java.awt.image.BufferedImage; + +public abstract class BMPDecoder { + + protected BMPInfoHeader infoHeader; + protected BMPFileHeader fileHeader; + protected long offset; + + public BMPDecoder(BMPFileHeader fh, BMPInfoHeader ih){ + fileHeader = fh; + infoHeader = ih; + offset = BMPFileHeader.SIZE + BMPInfoHeader.SIZE; + } + + /** + * Determines the coding type of the bitmap and returns the corresponding + * decoder. + */ + public static BMPDecoder getDecoder(BMPFileHeader fh, BMPInfoHeader ih){ + switch(ih.getCompression()){ + case BMPInfoHeader.BI_RGB: // uncompressed RGB + switch(ih.getBitCount()){ + case 32: + return new DecodeBF32(fh, ih, true); + + case 24: + return new DecodeRGB24(fh, ih); + + case 16: + return new DecodeBF16(fh, ih, true); + + case 8: + return new DecodeRGB8(fh, ih); + + case 4: + return new DecodeRGB4(fh, ih); + + case 1: + return new DecodeRGB1(fh, ih); + + default: + return null; + } + + case BMPInfoHeader.BI_RLE8: + return new DecodeRLE8(fh, ih); + + case BMPInfoHeader.BI_RLE4: + return new DecodeRLE4(fh, ih); + + case BMPInfoHeader.BI_BITFIELDS: + switch(ih.getBitCount()){ + case 16: + return new DecodeBF16(fh, ih, false); + + case 32: + return new DecodeBF32(fh, ih, false); + + default: + return null; + } + + default: + return null; + } + } + + /** + * The image decoder. + */ + public abstract BufferedImage decode(ImageInputStream in) + throws IOException, BMPException; + + /** + * Reads r,g,b bit masks from an inputstream + */ + protected int[] readBitMasks(ImageInputStream in) throws IOException { + int[] bitmasks = new int[3]; + byte[] temp = new byte[12]; + if(in.read(temp) != 12) + throw new IOException("Couldn't read bit masks."); + offset += 12; + + ByteBuffer buf = ByteBuffer.wrap(temp); + buf.order(ByteOrder.LITTLE_ENDIAN); + bitmasks[0] = buf.getInt(); + bitmasks[1] = buf.getInt(); + bitmasks[2] = buf.getInt(); + return bitmasks; + } + + /** + * Reads an N-color palette from an inputstream in RGBQUAD format and + * returns an equivalent ColorModel object + */ + protected IndexColorModel readPalette(ImageInputStream in) throws IOException { + int N = infoHeader.getNumberOfPaletteEntries(); + byte[] r = new byte[N]; + byte[] g = new byte[N]; + byte[] b = new byte[N]; + for(int i=0;i> 8) & 0x00FF); + return b; + } + + /** + * Converts an int to a double word, where the return value is + * stored in a 4-byte array. + * + * @param val - the value to convert + * @return the array + */ + private byte[] intToDWord(int val) + { + byte b[] = new byte[4]; + b[0] = (byte) (val & 0x00FF); + b[1] = (byte) ((val >> 8) & 0x000000FF); + b[2] = (byte) ((val >> 16) & 0x000000FF); + b[3] = (byte) ((val >> 24) & 0x000000FF); + return b; + } + + + public void setBitCount(short bitcount) throws BMPException + { + switch (bitcount) + { + case 1: + case 4: + case 8: + case 16: + case 24: + case 32: + biBitCount = bitcount; + break; + + default: + throw new BMPException("Invalid number of bits per pixel: " + bitcount); + } + } + + public short getBitCount() + { + return biBitCount; + } + + public void setCompression(int compression) throws BMPException + { + switch (compression) + { + case BI_RLE8: + if (getBitCount() != 8) + throw new BMPException("Invalid number of bits per pixel."); + biCompression = compression; + break; + case BI_RLE4: + if (getBitCount() != 4) + throw new BMPException("Invalid number of bits per pixel."); + biCompression = compression; + break; + + case BI_RGB: + case BI_BITFIELDS: + biCompression = compression; + break; + + default: + throw new BMPException("Unknown bitmap compression type."); + } + } + + public int getNumberOfPaletteEntries() + { + if (biClrUsed == 0) + switch (biBitCount) + { + case 1: + return 2; + case 4: + return 16; + case 8: + return 256; + + default: // should not happen + return 0; + } + + return biClrUsed; + } + + public int getCompression() + { + return biCompression; + } + + public Dimension getSize() + { + return new Dimension(biWidth, biHeight); + } + + public int getWidth() + { + return biWidth; + } + + public int getHeight() + { + return biHeight; + } + + public void setSize(Dimension d) + { + biWidth = (int) d.getWidth(); + biHeight = (int) d.getHeight(); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/bmp/DecodeBF16.java b/libjava/classpath/gnu/javax/imageio/bmp/DecodeBF16.java new file mode 100644 index 000000000..2f94ac613 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/bmp/DecodeBF16.java @@ -0,0 +1,99 @@ +/* DecodeBF16.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.bmp; + +import java.io.IOException; +import javax.imageio.stream.ImageInputStream; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferUShort; +import java.awt.image.SinglePixelPackedSampleModel; +import java.awt.image.SampleModel; +import java.awt.Dimension; + +public class DecodeBF16 extends BMPDecoder { + private int[] bitmasks; + private boolean useDefaultMasks; + + public DecodeBF16(BMPFileHeader fh, BMPInfoHeader ih, + boolean udm){ + super(fh,ih); + + useDefaultMasks = udm; + if(useDefaultMasks) // 5-6-5 mask, B,G,R + bitmasks = new int[] { 0x00F800, 0x0007E0, 0x00001F }; + } + + public BufferedImage decode(ImageInputStream in) throws IOException, BMPException { + if(!useDefaultMasks) + bitmasks = readBitMasks(in); + skipToImage(in); + + Dimension d = infoHeader.getSize(); + int h = (int)d.getHeight(); + int w = (int)d.getWidth(); + + // BMP scanlines are padded to dword offsets + int scansize = (w + (w&1)) << 1; + short[] data = new short[w*h]; + + for(int y=h-1;y>=0;y--){ + byte[] scanline = new byte[scansize]; + if(in.read(scanline) != scansize) + throw new IOException("Couldn't read image data."); + + for(int x=0;x=0;y--){ + byte[] scanline = new byte[scansize]; + if(in.read(scanline) != scansize) + throw new IOException("Couldn't read image data."); + + for(int x=0;x>3; + + int scansize = w>>3; + byte[] data = new byte[size]; + + for(int y=h-1;y>=0;y--){ + // Scanlines are padded to dword boundries + int readsize = scansize; + if((readsize & 3) != 0) readsize += (4 - (scansize & 3)); + + byte[] scanline = new byte[readsize]; + if(in.read(scanline) != readsize) + throw new IOException("Couldn't read image data."); + + for(int x=0;x=0;y--){ + byte[] scanline = new byte[scansize]; + if(in.read(scanline) != scansize) + throw new IOException("Couldn't read image data."); + + for(int x=0;x> 1; + + // Scanline padded to dword offsets + int wbytes = (w + (w & 1)) >> 1; + int scansize = ((wbytes & 3) != 0)? (wbytes + 4 - (wbytes&3)) : wbytes; + + byte[] data = new byte[wbytes*h]; + + for(int y=h-1;y>=0;y--){ + byte[] scanline = new byte[scansize]; + if(in.read(scanline) != scansize) + throw new IOException("Couldn't read image data."); + + for(int x=0;x=0;y--){ + byte[] scanline = new byte[scansize]; + if(in.read(scanline) != scansize) + throw new IOException("Couldn't read image data."); + + for(int x=0;x>1]; + int offIn = 0; + int x=0,y=0; + + // width in bytes + w += (w&1); + w = w >> 1; + + try { + while(((x>>1) + y*w) < w*h){ + if(in.read(cmd) != 2) + throw new IOException("Error reading compressed data."); + + if(cmd[0] == ESCAPE){ + switch(cmd[1]){ + case EOB: // end of bitmap + return data; + case EOL: // end of line + x = 0; + y++; + break; + case DELTA: // delta + if(in.read(cmd) != 2) + throw new IOException("Error reading compressed data."); + int dx = cmd[0] & (0xFF); + int dy = cmd[1] & (0xFF); + x += dx; + y += dy; + break; + + default: + // decode a literal run + int length = cmd[1] & (0xFF); + + // size of run, which is word aligned. + int bytesize = length; + bytesize += (bytesize & 1); + bytesize >>= 1; + bytesize += (bytesize & 1); + + byte[] run = new byte[bytesize]; + if(in.read(run) != bytesize) + throw new IOException("Error reading compressed data."); + + if((x&1) == 0){ + length += (length&1); + length >>= 1; + System.arraycopy(run, 0, data, ((x>>1) + w*(h-y-1)), + length); + } else { + for(int i=0;i>1) + w*(h-y-1)] + |= ((run[i>>1]&0xF0) >> 4); + else // copy low to high + data[((x+i)>>1) + w*(h-y-1)] + |= ((run[i>>1]&0x0F) << 4); + } + } + x += cmd[1] & (0xFF); + break; + } + } else { + // decode a byte run + int length = cmd[0] & (0xFF); + if((x&1) == 0){ + length += (length&1); + length >>= 1; + for(int i=0;i> 1)] = cmd[1]; + } else { + for(int i=0;i>1) + w*(h-y-1)] + |= ((cmd[1]&0xF0) >> 4); + else // copy low to high + data[((x+i)>>1) + w*(h-y-1)] + |= ((cmd[1]&0x0F) << 4); + } + } + x += cmd[0] & (0xFF); + } + } + return data; + } catch(ArrayIndexOutOfBoundsException e){ + throw new BMPException("Invalid RLE data."); + } + } +} diff --git a/libjava/classpath/gnu/javax/imageio/bmp/DecodeRLE8.java b/libjava/classpath/gnu/javax/imageio/bmp/DecodeRLE8.java new file mode 100644 index 000000000..afc3da89e --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/bmp/DecodeRLE8.java @@ -0,0 +1,142 @@ +/* DecodeRLE8.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.bmp; + +import java.io.IOException; +import javax.imageio.stream.ImageInputStream; +import java.awt.image.BufferedImage; +import java.awt.image.IndexColorModel; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.SinglePixelPackedSampleModel; +import java.awt.image.SampleModel; +import java.awt.Dimension; + +public class DecodeRLE8 extends BMPDecoder { + + public DecodeRLE8(BMPFileHeader fh, BMPInfoHeader ih){ + super(fh, ih); + } + + /** + * RLE control codes + */ + private static final byte ESCAPE = (byte)0; + private static final byte EOL = (byte)0; // end of line + private static final byte EOB = (byte)1; // end of bitmap + private static final byte DELTA = (byte)2; // delta + + public BufferedImage decode(ImageInputStream in) throws IOException, BMPException { + IndexColorModel palette = readPalette(in); + skipToImage(in); + + Dimension d = infoHeader.getSize(); + int h = (int)d.getHeight(); + int w = (int)d.getWidth(); + + byte[] data = uncompress(w, h, in); + SampleModel sm = new SinglePixelPackedSampleModel(DataBuffer.TYPE_BYTE, + w, h, + new int[] {0xFF}); + DataBuffer db = new DataBufferByte(data, w*h, 0); + WritableRaster raster = Raster.createWritableRaster(sm, db, null); + + return new BufferedImage(palette, raster, false, null); + } + + private byte[] uncompress(int w, int h, ImageInputStream in) + throws BMPException, IOException { + byte[] cmd = new byte[2]; + byte[] data = new byte[w*h]; + int offIn = 0; + int x=0,y=0; + + try { + while((x + y*w) < w*h){ + if(in.read(cmd) != 2) + throw new IOException("Error reading compressed data."); + + if(cmd[0] == ESCAPE){ + switch(cmd[1]){ + case EOB: // end of bitmap + return data; + case EOL: // end of line + x = 0; + y++; + break; + case DELTA: // delta + if(in.read(cmd) != 2) + throw new IOException("Error reading compressed data."); + int dx = cmd[0] & (0xFF); + int dy = cmd[1] & (0xFF); + x += dx; + y += dy; + break; + + default: + // decode a literal run + int length = cmd[1] & (0xFF); + int copylength = length; + + // absolute mode must be word-aligned + length += (length & 1); + + byte[] run = new byte[length]; + if(in.read(run) != length) + throw new IOException("Error reading compressed data."); + + System.arraycopy(run, 0, data, (x+w*(h-y-1)), + copylength); + x += copylength; + break; + } + } else { + // decode a byte run + int length = cmd[0] & (0xFF); + for(int i=0;i> 8 & 0xFF); + + o.write(rgb); + if (rowCount == infoHeader.biWidth) + { + rowCount = 1; + rowIndex = lastRowIndex - infoHeader.biWidth; + lastRowIndex = rowIndex; + } + else + rowCount++; + rowIndex++; + } + } + catch (Exception wb) + { + wb.printStackTrace(); + } + } +} diff --git a/libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB24.java b/libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB24.java new file mode 100644 index 000000000..7fbc83e2e --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB24.java @@ -0,0 +1,129 @@ +/* EncodeRGB24.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.imageio.bmp; + +import java.awt.image.BufferedImage; +import java.awt.image.PixelGrabber; +import java.io.IOException; + +import javax.imageio.IIOImage; +import javax.imageio.ImageWriteParam; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.stream.ImageOutputStream; + +public class EncodeRGB24 + extends BMPEncoder +{ + protected BMPInfoHeader infoHeader; + protected BMPFileHeader fileHeader; + protected long offset; + + /** + * Constructs an instance of this class. + * + * @param fh - the file header to use. + * @param ih - the info header to use. + */ + public EncodeRGB24(BMPFileHeader fh, BMPInfoHeader ih) + { + super(); + fileHeader = fh; + infoHeader = ih; + offset = BMPFileHeader.SIZE + BMPInfoHeader.SIZE; + } + + /** + * The image encoder. + * + * @param o - the image output stream + * @param streamMetadata - metadata associated with this stream, or + * null + * @param image - an IIOImage containing image data. + * @param param - image writing parameters, or null + * @exception IOException if a write error occurs + */ + public void encode(ImageOutputStream o, IIOMetadata streamMetadata, + IIOImage image, ImageWriteParam param) throws IOException + { + int size; + int value; + int j; + int rowCount; + int rowIndex; + int lastRowIndex; + int[] bitmap; + byte rgb[] = new byte[3]; + size = (infoHeader.biWidth * infoHeader.biHeight) - 1; + rowCount = 1; + rowIndex = size - infoHeader.biWidth; + lastRowIndex = rowIndex; + try + { + bitmap = new int[infoHeader.biWidth * infoHeader.biHeight]; + PixelGrabber pg = new PixelGrabber((BufferedImage) image.getRenderedImage(), + 0, 0, infoHeader.biWidth, + infoHeader.biHeight, bitmap, 0, + infoHeader.biWidth); + pg.grabPixels(); + + for (j = 0; j < size; j++) + { + value = bitmap[rowIndex]; + + rgb[0] = (byte) (value & 0xFF); + rgb[1] = (byte) ((value >> 8) & 0xFF); + rgb[2] = (byte) ((value >> 16) & 0xFF); + o.write(rgb); + if (rowCount == infoHeader.biWidth) + { + rowCount = 1; + rowIndex = lastRowIndex - infoHeader.biWidth; + lastRowIndex = rowIndex; + } + else + rowCount++; + rowIndex++; + } + } + catch (Exception wb) + { + wb.printStackTrace(); + } + } +} diff --git a/libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB32.java b/libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB32.java new file mode 100644 index 000000000..7deca3049 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB32.java @@ -0,0 +1,129 @@ +/* EncodeRGB32.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.imageio.bmp; + +import java.awt.image.BufferedImage; +import java.awt.image.PixelGrabber; +import java.io.IOException; + +import javax.imageio.IIOImage; +import javax.imageio.ImageWriteParam; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.stream.ImageOutputStream; + +public class EncodeRGB32 + extends BMPEncoder +{ + protected BMPInfoHeader infoHeader; + protected BMPFileHeader fileHeader; + protected long offset; + + /** + * Constructs an instance of this class. + * + * @param fh - the file header to use. + * @param ih - the info header to use. + */ + public EncodeRGB32(BMPFileHeader fh, BMPInfoHeader ih) + { + super(); + fileHeader = fh; + infoHeader = ih; + offset = BMPFileHeader.SIZE + BMPInfoHeader.SIZE; + } + + /** + * The image encoder. + * + * @param o - the image output stream + * @param streamMetadata - metadata associated with this stream, or null + * @param image - an IIOImage containing image data. + * @param param - image writing parameters, or null + * @exception IOException if a write error occurs + */ + public void encode(ImageOutputStream o, IIOMetadata streamMetadata, + IIOImage image, ImageWriteParam param) throws IOException + { + int size; + int value; + int j; + int rowCount; + int rowIndex; + int lastRowIndex; + int[] bitmap; + byte rgb[] = new byte[4]; + size = (infoHeader.biWidth * infoHeader.biHeight) - 1; + rowCount = 1; + rowIndex = size - infoHeader.biWidth; + lastRowIndex = rowIndex; + try + { + bitmap = new int[infoHeader.biWidth * infoHeader.biHeight]; + PixelGrabber pg = new PixelGrabber((BufferedImage) image.getRenderedImage(), + 0, 0, infoHeader.biWidth, + infoHeader.biHeight, bitmap, 0, + infoHeader.biWidth); + pg.grabPixels(); + + for (j = 0; j < size; j++) + { + value = bitmap[rowIndex]; + + rgb[0] = (byte) (value & 0xFF); + rgb[1] = (byte) ((value >> 8) & 0xFF); + rgb[2] = (byte) ((value >> 16) & 0xFF); + rgb[3] = (byte) ((value >> 24) & 0xFF); + o.write(rgb); + if (rowCount == infoHeader.biWidth) + { + rowCount = 1; + rowIndex = lastRowIndex - infoHeader.biWidth; + lastRowIndex = rowIndex; + } + else + rowCount++; + rowIndex++; + } + } + catch (Exception wb) + { + wb.printStackTrace(); + } + } +} diff --git a/libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB4.java b/libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB4.java new file mode 100644 index 000000000..b62283a7d --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB4.java @@ -0,0 +1,128 @@ +/* EncodeRGB4.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.imageio.bmp; + +import java.awt.image.BufferedImage; +import java.awt.image.PixelGrabber; +import java.io.IOException; + +import javax.imageio.IIOImage; +import javax.imageio.ImageWriteParam; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.stream.ImageOutputStream; + +public class EncodeRGB4 + extends BMPEncoder +{ + protected BMPInfoHeader infoHeader; + protected BMPFileHeader fileHeader; + protected long offset; + + /** + * Constructs an instance of this class. + * + * @param fh - the file header to use. + * @param ih - the info header to use. + */ + public EncodeRGB4(BMPFileHeader fh, BMPInfoHeader ih) + { + super(); + fileHeader = fh; + infoHeader = ih; + offset = BMPFileHeader.SIZE + BMPInfoHeader.SIZE; + } + + /** + * The image encoder. + * + * @param o - the image output stream + * @param streamMetadata - metadata associated with this stream, or + * null + * @param image - an IIOImage containing image data. + * @param param - image writing parameters, or null + * @exception IOException if a write error occurs + */ + public void encode(ImageOutputStream o, IIOMetadata streamMetadata, + IIOImage image, ImageWriteParam param) throws IOException + { + int size; + int value; + int j; + int rowCount; + int rowIndex; + int lastRowIndex; + int[] bitmap; + byte rgb[] = new byte[1]; + size = (infoHeader.biWidth * infoHeader.biHeight) - 1; + rowCount = 1; + rowIndex = size - infoHeader.biWidth; + lastRowIndex = rowIndex; + try + { + bitmap = new int[infoHeader.biWidth * infoHeader.biHeight]; + PixelGrabber pg = new PixelGrabber((BufferedImage) image.getRenderedImage(), + 0, 0, infoHeader.biWidth, + infoHeader.biHeight, bitmap, 0, + infoHeader.biWidth); + pg.grabPixels(); + + for (j = 0; j < size; j++) + { + value = bitmap[rowIndex]; + + rgb[0] = (byte) (value & 0xFF); + + o.write(rgb); + if (rowCount == infoHeader.biWidth) + { + rowCount = 1; + rowIndex = lastRowIndex - infoHeader.biWidth; + lastRowIndex = rowIndex; + } + else + rowCount++; + rowIndex++; + } + } + catch (Exception wb) + { + wb.printStackTrace(); + } + } +} diff --git a/libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB8.java b/libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB8.java new file mode 100644 index 000000000..ef0594a5f --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB8.java @@ -0,0 +1,127 @@ +/* EncodeRGB8.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.imageio.bmp; + +import java.awt.image.BufferedImage; +import java.awt.image.PixelGrabber; +import java.io.IOException; + +import javax.imageio.IIOImage; +import javax.imageio.ImageWriteParam; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.stream.ImageOutputStream; + +public class EncodeRGB8 + extends BMPEncoder +{ + protected BMPInfoHeader infoHeader; + protected BMPFileHeader fileHeader; + protected long offset; + + /** + * Constructs an instance of this class. + * + * @param fh - the file header to use. + * @param ih - the info header to use. + */ + public EncodeRGB8(BMPFileHeader fh, BMPInfoHeader ih) + { + super(); + fileHeader = fh; + infoHeader = ih; + offset = BMPFileHeader.SIZE + BMPInfoHeader.SIZE; + } + + /** + * The image encoder. + * + * @param o - the image output stream + * @param streamMetadata - metadata associated with this stream, or + * null + * @param image - an IIOImage containing image data. + * @param param - image writing parameters, or null + * @exception IOException if a write error occurs + */ + public void encode(ImageOutputStream o, IIOMetadata streamMetadata, + IIOImage image, ImageWriteParam param) throws IOException + { + int size; + int value; + int j; + int rowCount; + int rowIndex; + int lastRowIndex; + int[] bitmap; + byte rgb[] = new byte[1]; + size = (infoHeader.biWidth * infoHeader.biHeight) - 1; + rowCount = 1; + rowIndex = size - infoHeader.biWidth; + lastRowIndex = rowIndex; + try + { + bitmap = new int[infoHeader.biWidth * infoHeader.biHeight]; + PixelGrabber pg = new PixelGrabber((BufferedImage) image.getRenderedImage(), + 0, 0, infoHeader.biWidth, + infoHeader.biHeight, bitmap, 0, + infoHeader.biWidth); + pg.grabPixels(); + + for (j = 0; j < size; j++) + { + value = bitmap[rowIndex]; + + rgb[0] = (byte) (value & 0xFF); + o.write(rgb); + if (rowCount == infoHeader.biWidth) + { + rowCount = 1; + rowIndex = lastRowIndex - infoHeader.biWidth; + lastRowIndex = rowIndex; + } + else + rowCount++; + rowIndex++; + } + } + catch (Exception wb) + { + wb.printStackTrace(); + } + } +} diff --git a/libjava/classpath/gnu/javax/imageio/bmp/EncodeRLE4.java b/libjava/classpath/gnu/javax/imageio/bmp/EncodeRLE4.java new file mode 100644 index 000000000..c54c3ca87 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/bmp/EncodeRLE4.java @@ -0,0 +1,269 @@ +/* EncodeRLE4.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.imageio.bmp; + +import java.awt.image.BufferedImage; +import java.awt.image.PixelGrabber; +import java.io.IOException; +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; + +import javax.imageio.IIOImage; +import javax.imageio.ImageWriteParam; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.stream.ImageOutputStream; + +public class EncodeRLE4 + extends BMPEncoder +{ + protected BMPInfoHeader infoHeader; + protected BMPFileHeader fileHeader; + protected long offset; + + /** + * RLE control codes + */ + private static final byte ESCAPE = (byte)0; + private static final byte EOL = (byte)0; // end of line + private static final byte EOB = (byte)1; // end of bitmap + private static final byte DELTA = (byte)2; // delta + + /** + * Constructs an instance of this class. + * + * @param fh - the file header to use. + * @param ih - the info header to use. + */ + public EncodeRLE4(BMPFileHeader fh, BMPInfoHeader ih) + { + super(); + fileHeader = fh; + infoHeader = ih; + offset = BMPFileHeader.SIZE + BMPInfoHeader.SIZE; + } + + /** + * The image encoder. + * + * @param o - the image output stream + * @param streamMetadata - metadata associated with this stream, or + * null + * @param image - an IIOImage containing image data. + * @param param - image writing parameters, or null + * @exception IOException if a write error occurs + */ + public void encode(ImageOutputStream o, IIOMetadata streamMetadata, + IIOImage image, ImageWriteParam param) throws IOException + { + int size; + int value; + int j; + int rowCount; + int rowIndex; + int lastRowIndex; + int[] bitmap; + size = (infoHeader.biWidth * infoHeader.biHeight) - 1; + rowCount = 1; + rowIndex = size - infoHeader.biWidth; + lastRowIndex = rowIndex; + ByteBuffer buf = ByteBuffer.allocate(size); + try + { + bitmap = new int[infoHeader.biWidth * infoHeader.biHeight]; + PixelGrabber pg = new PixelGrabber((BufferedImage) image.getRenderedImage(), + 0, 0, infoHeader.biWidth, + infoHeader.biHeight, bitmap, 0, + infoHeader.biWidth); + pg.grabPixels(); + + for (j = 0; j < size; j++) + { + value = bitmap[rowIndex]; + buf.put((byte) (value & 0xFF)); + + if (rowCount == infoHeader.biWidth) + { + rowCount = 1; + rowIndex = lastRowIndex - infoHeader.biWidth; + lastRowIndex = rowIndex; + } + else + rowCount++; + rowIndex++; + } + + buf.flip(); + o.write(uncompress(infoHeader.biWidth, infoHeader.biHeight, buf)); + } + catch (Exception wb) + { + wb.printStackTrace(); + } + } + + /** + * Uncompresses the image stored in the buffer. + * + * @param w - the width of the image + * @param h - the height of the image + * @param buf - the ByteBuffer containing the pixel values. + * @return byte array containing the uncompressed image + * @throws IOException if an error is encountered while reading + * buffer. + */ + private byte[] uncompress(int w, int h, ByteBuffer buf) + throws IOException + { + byte[] cmd = new byte[2]; + byte[] data = new byte[w * h >> 1]; + int offIn = 0; + int x = 0, y = 0; + + w += (w & 1); + w = w >> 1; + + try + { + while (((x >> 1) + y * w) < w * h) + { + try + { + buf.get(cmd); + } + catch (BufferUnderflowException e) + { + throw new IOException("Error reading compressed data."); + } + + if (cmd[0] == ESCAPE) + { + switch (cmd[1]) + { + case EOB: + return data; + case EOL: + x = 0; + y++; + break; + case DELTA: + try + { + buf.get(cmd); + } + catch (BufferUnderflowException e) + { + throw new IOException("Error reading compressed data."); + } + + int dx = cmd[0] & (0xFF); + int dy = cmd[1] & (0xFF); + x += dx; + y += dy; + break; + + default: + int length = cmd[1] & (0xFF); + + int bytesize = length; + bytesize += (bytesize & 1); + bytesize >>= 1; + bytesize += (bytesize & 1); + + byte[] run = new byte[bytesize]; + try + { + buf.get(run); + } + catch (BufferUnderflowException e) + { + throw new IOException("Error reading compressed data."); + } + + if ((x & 1) == 0) + { + length += (length & 1); + length >>= 1; + System.arraycopy(run, 0, data, + ((x >> 1) + w * (h - y - 1)), length); + } + else + { + for (int i = 0; i < length; i++) + { + if ((i & 1) == 0) + data[((x + i) >> 1) + w * (h - y - 1)] |= ((run[i >> 1] & 0xF0) >> 4); + else + data[((x + i) >> 1) + w * (h - y - 1)] |= ((run[i >> 1] & 0x0F) << 4); + } + } + x += cmd[1] & (0xFF); + break; + } + } + else + { + int length = cmd[0] & (0xFF); + if ((x & 1) == 0) + { + length += (length & 1); + length >>= 1; + for (int i = 0; i < length; i++) + data[(h - y - 1) * w + i + (x >> 1)] = cmd[1]; + } + else + { + for (int i = 0; i < length; i++) + { + if ((i & 1) == 0) + data[((x + i) >> 1) + w * (h - y - 1)] |= ((cmd[1] & 0xF0) >> 4); + else + data[((x + i) >> 1) + w * (h - y - 1)] |= ((cmd[1] & 0x0F) << 4); + } + } + x += cmd[0] & (0xFF); + } + } + return data; + } + catch (ArrayIndexOutOfBoundsException e) + { + throw new BMPException("Invalid RLE data."); + } + } +} diff --git a/libjava/classpath/gnu/javax/imageio/bmp/EncodeRLE8.java b/libjava/classpath/gnu/javax/imageio/bmp/EncodeRLE8.java new file mode 100644 index 000000000..62277ef90 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/bmp/EncodeRLE8.java @@ -0,0 +1,234 @@ +/* EncodeRGB32.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.imageio.bmp; + +import java.awt.image.BufferedImage; +import java.awt.image.PixelGrabber; +import java.io.IOException; +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; + +import javax.imageio.IIOImage; +import javax.imageio.ImageWriteParam; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.stream.ImageOutputStream; + +public class EncodeRLE8 + extends BMPEncoder +{ + protected BMPInfoHeader infoHeader; + protected BMPFileHeader fileHeader; + protected long offset; + + /** + * RLE control codes + */ + private static final byte ESCAPE = (byte)0; + private static final byte EOL = (byte)0; // end of line + private static final byte EOB = (byte)1; // end of bitmap + private static final byte DELTA = (byte)2; // delta + + /** + * Constructs an instance of this class. + * + * @param fh - the file header to use. + * @param ih - the info header to use. + */ + public EncodeRLE8(BMPFileHeader fh, BMPInfoHeader ih) + { + super(); + fileHeader = fh; + infoHeader = ih; + offset = BMPFileHeader.SIZE + BMPInfoHeader.SIZE; + } + + /** + * The image encoder. + * + * @param o - the image output stream + * @param streamMetadata - metadata associated with this stream, or + * null + * @param image - an IIOImage containing image data. + * @param param - image writing parameters, or null + * @exception IOException if a write error occurs + */ + public void encode(ImageOutputStream o, IIOMetadata streamMetadata, + IIOImage image, ImageWriteParam param) throws IOException + { + int size; + int value; + int j; + int rowCount; + int rowIndex; + int lastRowIndex; + int[] bitmap; + size = (infoHeader.biWidth * infoHeader.biHeight) - 1; + rowCount = 1; + rowIndex = size - infoHeader.biWidth; + lastRowIndex = rowIndex; + ByteBuffer buf = ByteBuffer.allocate(size); + try + { + bitmap = new int[infoHeader.biWidth * infoHeader.biHeight]; + PixelGrabber pg = new PixelGrabber((BufferedImage) image.getRenderedImage(), + 0, 0, infoHeader.biWidth, + infoHeader.biHeight, bitmap, 0, + infoHeader.biWidth); + pg.grabPixels(); + + for (j = 0; j < size; j++) + { + value = bitmap[rowIndex]; + buf.put((byte) (value & 0xFF)); + + if (rowCount == infoHeader.biWidth) + { + rowCount = 1; + rowIndex = lastRowIndex - infoHeader.biWidth; + lastRowIndex = rowIndex; + } + else + rowCount++; + rowIndex++; + } + + buf.flip(); + o.write(uncompress(infoHeader.biWidth, infoHeader.biHeight, buf)); + } + catch (Exception wb) + { + wb.printStackTrace(); + } + } + + + /** + * Uncompresses the image stored in the buffer. + * + * @param w - the width of the image + * @param h - the height of the image + * @param buf - the ByteBuffer containing the pixel values. + * @return byte array containing the uncompressed image + * @throws IOException if an error is encountered while reading + * buffer. + */ + private byte[] uncompress(int w, int h, ByteBuffer buf) throws IOException + { + byte[] cmd = new byte[2]; + byte[] data = new byte[w * h]; + int offIn = 0; + int x = 0, y = 0; + + try + { + while ((x + y * w) < w * h) + { + try + { + buf.get(cmd); + } + catch (BufferUnderflowException e) + { + throw new IOException("Error reading compressed data."); + } + + if (cmd[0] == ESCAPE) + { + switch (cmd[1]) + { + case EOB: + return data; + case EOL: + x = 0; + y++; + break; + case DELTA: + try + { + buf.get(cmd); + } + catch (BufferUnderflowException e) + { + throw new IOException("Error reading compressed data."); + } + + int dx = cmd[0] & (0xFF); + int dy = cmd[1] & (0xFF); + x += dx; + y += dy; + break; + + default: + int length = cmd[1] & (0xFF); + int copylength = length; + + length += (length & 1); + + byte[] run = new byte[length]; + + try + { + buf.get(run); + } + catch (BufferUnderflowException e) + { + throw new IOException("Error reading compressed data."); + } + + System.arraycopy(run, 0, data, (x + w * (h - y - 1)), + copylength); + x += copylength; + break; + } + } + else + { + int length = cmd[0] & (0xFF); + for (int i = 0; i < length; i++) + data[(h - y - 1) * w + x++] = cmd[1]; + } + } + return data; + } + catch (ArrayIndexOutOfBoundsException e) + { + throw new BMPException("Invalid RLE data."); + } + } +} diff --git a/libjava/classpath/gnu/javax/imageio/gif/GIFFile.java b/libjava/classpath/gnu/javax/imageio/gif/GIFFile.java new file mode 100644 index 000000000..941397a0e --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/gif/GIFFile.java @@ -0,0 +1,709 @@ +/* GIFFile.java -- GIF decoder + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.gif; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Vector; + +/** + * GIFFile - reads a GIF file. + * + * This class only does the bare minimum work, and returns the data in raw + * formats (described below). The class is J2ME compatible, and hopefully + * we can keep it that way without any significant overhead. + * + * @author Sven de Marothy. + */ +public class GIFFile +{ + // "NETSCAPE2.0" - identifier + private final static byte[] nsBlock = new byte[] + {0x4e, 0x45, 0x54, 0x53, 0x43, 0x41, 0x50, 0x45, 0x32, 0x2e, 0x30 }; + + /** + * Block identifiers + */ + private final static int EXTENSION = 0x21; + private final static int LOCAL = 0x2C; + private final static int TERMINATOR = 0x3B; + + /** + * Extension block types + */ + private final static int EXTENSION_COMMENT = 254; + private final static int EXTENSION_GCONTROL = 249; + private final static int EXTENSION_APPLICATION = 255; + + /** + * Undraw commands for animation. + */ + private final static int UNDRAW_OVERWRITE = 1; + private final static int UNDRAW_RESTORE_BACKGROUND = 2; + private final static int UNDRAW_RESTORE_PREVIOUS = 3; + + /** + * Image position and dimensions (images may be partial) + */ + private int x, y, width, height; + + /** + * Global dimensions + */ + private int globalWidth, globalHeight; + + /** + * Background color index. + */ + private byte bgIndex; + + /** + * Number of colors + */ + private int nColors; + + /** + * Global palette, if any + */ + private byte[] globalPalette; + + /** + * Any + */ + private boolean hasGlobalColorMap; + + /** + * Local palette, if any (used if available) + */ + private byte[] localPalette; + + /** + * Interlaced GIF or not? + */ + private boolean interlaced; + + /** + * Has transparency? + */ + private boolean hasTransparency; + + /** + * Undraw mode (animations) + */ + private int undraw; + + /** + * Transparent index; + */ + private int transparentIndex; + + /** + * The uncompressed raster + */ + private byte[] raster; + + /** + * The compressed data (freed after uncompressing) + */ + private byte[] compressedData; + + /** + * Frame delay in 100ths of a second ( centiseconds, metrically ) + */ + private int duration; + + /** + * Indices used during decompression + */ + private int dataBlockIndex; + + /** + * The file comment , if a comment block exists. + */ + private String comment; + + /** + * Fields used by getBits() + */ + private int remainingBits = 0; + private int currentBits = 0; + + /** + * Netscape animation extension + */ + private boolean isLooped = false; + + /** Number of loops, 0 = infinite */ + private int loops; + + /** + * Additional frames if it's an animated GIF. + */ + private Vector animationFrames; + + /** + * Loads the file from an input stream, which is not closed. + * @throws IOException if an I/O error occured. + * @throws GIFException if some file parsing error occured + */ + public GIFFile(InputStream in) throws IOException, GIFException + { + // Validate the signature + if( !readSignature( in ) ) + throw new GIFException("Invalid GIF signature."); + + { + byte[] data = new byte[7]; + if (in.read(data) != 7) + throw new IOException("Couldn't read global descriptor."); + + globalWidth = ((data[1] & 0xFF) << 8) | (data[0] & 0xFF); + globalHeight = ((data[3] & 0xFF) << 8) | (data[2] & 0xFF); + byte flags = data[4]; + bgIndex = data[5]; + nColors = (1 << (( flags & 0x07) + 1)); + hasGlobalColorMap = ((flags & 0x80) != 0); + } + + if( hasGlobalColorMap ) + { + globalPalette = new byte[ nColors * 3 ]; + if( in.read( globalPalette ) != nColors * 3 ) + throw new IOException("Couldn't read color map."); + } + + int c = in.read(); + while( c == EXTENSION ) + { + readExtension( in ); + c = in.read(); + } + + if( c != LOCAL ) + throw new GIFException("Extension blocks not followed by a local descriptor ("+c+")"); + + loadImage( in ); + c = in.read(); + + if( c == TERMINATOR ) // Not an animated GIF. + return; + + // Load animation frames. Just quit if an error occurs instead + // of throwing an exception. + animationFrames = new Vector(); + try + { + while( c != TERMINATOR ) + { + animationFrames.add( new GIFFile( this, in, c ) ); + c = in.read(); + } + } + catch(IOException ioe) + { + } + catch(GIFException gife) + { + } + } + + /** + * Constructor for additional animation frames. + */ + private GIFFile(GIFFile parent, InputStream in, int c) + throws IOException, GIFException + { + // Copy global properties. + globalWidth = parent.globalWidth; + globalHeight = parent.globalHeight; + nColors = parent.nColors; + globalPalette = parent.globalPalette; + hasGlobalColorMap = parent.hasGlobalColorMap; + interlaced = parent.interlaced; + comment = parent.comment; + isLooped = parent.isLooped; + loops = parent.loops; + + while( c == EXTENSION ) + { + readExtension( in ); + c = in.read(); + } + + if( c != LOCAL ) + throw new GIFException("Extension blocks not followed by a local descriptor ("+c+")"); + + loadImage( in ); + } + + /** + * Reads a GIF file signature from an inputstream and checks it. + * + * @param in - the stream (reads 6 bytes, does not close or reset). + * @return true if the signature is a valid GIF signature. + * @throws IOException if the signature could not be read. + */ + public static boolean readSignature( InputStream in ) throws IOException + { + byte[] data = new byte[6]; + if (in.read(data) != 6) + throw new IOException("Couldn't read signature."); + + if( data[0] != 0x47 || data[1] != 0x49 || data[2] != 0x46 || + data[3] != 0x38 ) // GIF8 + return false; + + if( (data[4] != 0x39 && data[4] != 0x37) || // 7 | 9 + (data[5] != 0x61 && data[5] != 0x62) ) // 'a' or 'b' + return false; + return true; + } + + + /** + * Loads the image local descriptor and then loads/decodes the image raster, + * and then performs any necessary postprocessing like deinterlacing. + */ + private void loadImage(InputStream in) + throws IOException, GIFException + { + readLocal( in ); + + try + { + decodeRaster( in ); + } + catch(ArrayIndexOutOfBoundsException aioobe) + { + throw new GIFException("Error decompressing image."); + } + + if( interlaced ) // Clean up + deinterlace(); + packPixels(); + } + + /** + * Pack the pixels if it's a 2, 4 or 16 color image. + * While GIF may support any number of colors from 2-256, we won't bother + * trying to pack pixels not resulting in even byte boundaries. + * (AWT doesn't support that anyway, and most apps do the same.) + */ + private void packPixels() + { + if( nColors != 2 && nColors != 4 && nColors != 16 ) + return; + + int nbits = 1; + int ppbyte = 8; + if( nColors == 4 ) + { + nbits = 2; + ppbyte = 4; + } + else if( nColors == 16 ) + { + nbits = 4; + ppbyte = 2; + } + + int rem = (width & (ppbyte - 1)); + int w = ( rem == 0 ) ? (width / ppbyte) : + ((width + ppbyte - rem) / ppbyte); + byte[] nr = new byte[ w * height ]; + for(int j = 0; j < height; j++) + { + for(int i = 0; i < width - ppbyte; i += ppbyte) + for(int k = 0; k < ppbyte; k++) + nr[ j * w + (i / ppbyte) ] |= (byte)((raster[ width * j + i + k ] + << (8 - nbits * (1 + k)))); + for(int i = 0; i < rem; i++) + nr[ j * w + w - 1 ] |= (byte)((raster[ width * j + width - rem + i ] + << (nbits * (rem - i)))); + } + raster = nr; + } + + /** + * Returns the (global) width + */ + public int getWidth() + { + return width; + } + + /** + * Returns the image height + */ + public int getHeight() + { + return height; + } + + /** + * Returns the # of colors. + */ + public int getNColors() + { + return nColors; + } + + /** + * Returns whether the GIF has transparency. + */ + public boolean hasTransparency() + { + return hasTransparency; + } + + /** + * Returns the index of the transparent color. + */ + public int getTransparentIndex() + { + return transparentIndex; + } + + /** + * Retuns the GIF file comment, or null if none exists. + */ + public String getComment() + { + return comment; + } + + /** + * Get duration of the frame for animations. + */ + public int getDuration() + { + return duration; + } + + /** + * Deinterlaces the image. + */ + private void deinterlace() + { + byte[] nr = new byte[ width * height ]; + int n = 0; + for(int i = 0; i < ((height + 7) >> 3); i++) + { + System.arraycopy( raster, n, nr, width * i * 8, width ); + n += width; + } + for(int i = 0; i < ((height + 3) >> 3); i++) + { + System.arraycopy( raster, n, nr, width * ( 8 * i + 4 ), width ); + n += width; + } + for(int i = 0; i < (height >> 2); i++) + { + System.arraycopy( raster, n, nr, width * (4 * i + 2), width ); + n += width; + } + for(int i = 0; i < (height >> 1); i++) + { + System.arraycopy( raster, n, nr, width * (2 * i + 1), width ); + n += width; + } + raster = nr; + } + + /** + * Reads the local descriptor + */ + private void readLocal(InputStream in) throws IOException + { + byte[] data = new byte[9]; + if (in.read(data) != 9) + throw new IOException("Couldn't read local descriptor."); + x = ((data[1] & 0xFF) << 8) | (data[0] & 0xFF); + y = ((data[3] & 0xFF) << 8) | (data[2] & 0xFF); + width = ((data[5] & 0xFF) << 8) | (data[4] & 0xFF); + height = ((data[7] & 0xFF) << 8) | (data[6] & 0xFF); + byte flags = data[8]; + interlaced = (( flags & 0x40 ) != 0); + if( (flags & 0x80) != 0 ) + { // has a local color map + int nLocalColors = (1 << (( flags & 0x07) + 1)); + if( !hasGlobalColorMap ) + nColors = nLocalColors; + localPalette = new byte[ nLocalColors * 3 ]; + if( in.read( localPalette ) != nLocalColors * 3 ) + throw new IOException("Couldn't read color map."); + } + } + + /** + * Returns the image's palette in raw format + * (r0,g0,b0,r1,g1,b2..r(Ncolors-1),g(Ncolors-1),b(Ncolors-1)) + */ + public byte[] getRawPalette() + { + return hasGlobalColorMap ? globalPalette : localPalette; + } + + /** + * Returns the image file for animated gifs. + */ + public GIFFile getImage( int index ) + { + if( index == 0 ) + return this; + if( animationFrames == null ) + throw new ArrayIndexOutOfBoundsException("Only one image in file"); + return (GIFFile)animationFrames.elementAt( index - 1 ); + } + + /** + * Return the image's raw image data. + * If the color depth is 1,2 or 4 bits per pixel the pixels are packed + * and the scanlines padded up to the nearest byte if needed. + */ + public byte[] getRawImage() + { + return raster; + } + + /** + * Return the number of images in the GIF file + */ + public int nImages() + { + if( animationFrames != null ) + return 1 + animationFrames.size(); + return 1; + } + + /** + * Handles extension blocks. + */ + private void readExtension(InputStream in) throws IOException, GIFException + { + int functionCode = in.read(); + byte[] data = readData(in); + switch( functionCode ) + { + case EXTENSION_COMMENT: // comment block + comment = new String(data, "8859_1"); + break; + + case EXTENSION_GCONTROL: // Graphics control extension + undraw = (data[0] & 0x1C) >> 2; + // allegedly there can be bad values of this. + if( undraw < 1 && undraw > 3 ) undraw = 1; + hasTransparency = ((data[0] & 0x01) == 1); + transparentIndex = (data[3] & 0xFF); + duration = ((data[2] & 0xFF) << 8) | (data[1] & 0xFF); + break; + + // Application extension. We only parse the Netscape animation + // extension here. Which is the only one most use anyway. + case EXTENSION_APPLICATION: + boolean isNS = true; + for(int i = 0; i < nsBlock.length; i++ ) + if( nsBlock[i] != data[i] ) + isNS = false; + if( isNS ) + { + isLooped = true; + loops = ((data[12] & 0xFF) << 8) | (data[13] & 0xFF); + } + break; + + default: + break; + } + } + + /** + * Reads a series of data blocks and merges them into a single one. + */ + private byte[] readData(InputStream in) throws IOException + { + Vector v = new Vector(); + int totalBytes = 0; + + int n = in.read(); + do + { + totalBytes += n; + byte[] block = new byte[ n ]; + in.read(block); + v.add(block); + n = in.read(); + } + while( n > 0 ); + + n = 0; + byte[] bigBuffer = new byte[ totalBytes ]; + for( int i = 0; i < v.size(); i++ ) + { + byte[] block = (byte[])v.elementAt(i); + System.arraycopy(block, 0, bigBuffer, n, block.length); + n += block.length; + } + return bigBuffer; + } + + /** + * Loads a compressed image block and decompresses it. + */ + private void decodeRaster(InputStream in) throws IOException + { + int initialCodeSize = in.read(); + compressedData = readData( in ); + dataBlockIndex = 0; + + int rasterIndex = 0; // Index into the raster + int clearCode = (1 << initialCodeSize); // 256 usually + int endCode = clearCode + 1; // The stop code. + + raster = new byte[ width * height ]; + + int codeSize = initialCodeSize + 1; + int code = getBits( codeSize ); // = clear + int nextCode = endCode + 1; + + /* + * Initialize LZW dictionary + * + * First index - code # + * Second index: + * 0 = color index + * 1 = parent (-1 - no parent) + * 2 = first value + * 3 - depth + * The latter two aren't strictly necessary but make things faster, since + * copying the values forward is faster than going back and looking. + */ + short[][] dictionary = new short[ 4096 ][ 4 ]; + + for(short i = 0; i < nColors; i ++ ) + { + dictionary[i][0] = i; // color index + dictionary[i][1] = -1; // parent + dictionary[i][2] = i; // first + dictionary[i][3] = 1; // depth + } + + code = getBits( codeSize ); // get second code + raster[ rasterIndex++ ] = (byte)dictionary[code][0]; + int old = code; + code = getBits( codeSize ); // start at the third code + int c; + + do + { + if( code == clearCode ) + { + codeSize = initialCodeSize + 1; + nextCode = endCode + 1; + // get and output second code + code = getBits( codeSize ); + raster[ rasterIndex++ ] = (byte)dictionary[code][0]; + old = code; + } + else + { + dictionary[nextCode][1] = (short)old; // parent = old + dictionary[nextCode][2] = dictionary[old][2]; // first pixel + dictionary[nextCode][3] = (short)(dictionary[old][3] + 1); // depth + + // appended pixel = first pixel of c + if( code < nextCode ) + { + dictionary[nextCode][0] = dictionary[code][2]; + old = code; + } + else // first of old + { + dictionary[nextCode][0] = dictionary[old][2]; + old = nextCode; + } + + c = old; + // output the code c + int depth = dictionary[c][3]; + for( int i = depth - 1; i >= 0; i-- ) + { + raster[ rasterIndex + i ] = (byte)dictionary[c][0]; + c = dictionary[c][1]; // go to parent. + } + rasterIndex += depth; + nextCode ++; + + if( codeSize < 12 && nextCode >= (1 << codeSize) ) + codeSize++; + } + code = getBits( codeSize ); + } + while( code != endCode && dataBlockIndex < compressedData.length ); + + compressedData = null; // throw away compressed data. + } + + /** + * Returns nbits number of bits (in the LSBs) from compressedData + */ + private int getBits( int nbits ) + { + while( nbits > remainingBits ) + { + int c = (compressedData[ dataBlockIndex++ ] & 0xFF) << remainingBits; + currentBits |= c; + remainingBits += 8; + } + int rval = (currentBits & ((1 << nbits) - 1)); + currentBits = (currentBits >> nbits); + remainingBits -= nbits; + return rval; + } + + /** + * Generic exception used by GIFFile to report decoding errors. + */ + public static class GIFException extends Exception + { + public GIFException(String message) + { + super(message); + } + } +} diff --git a/libjava/classpath/gnu/javax/imageio/gif/GIFImageReader.java b/libjava/classpath/gnu/javax/imageio/gif/GIFImageReader.java new file mode 100644 index 000000000..2cb59226b --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/gif/GIFImageReader.java @@ -0,0 +1,241 @@ +/* GIFImageReader.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.gif; + +import gnu.javax.imageio.IIOInputStream; + +import java.io.IOException; +import java.io.InputStream; +import javax.imageio.*; +import javax.imageio.spi.*; +import javax.imageio.metadata.*; +import javax.imageio.stream.ImageInputStream; +import java.util.Iterator; +import java.awt.image.BufferedImage; +import java.awt.image.IndexColorModel; +import java.awt.image.SampleModel; +import java.awt.image.MultiPixelPackedSampleModel; +import java.awt.image.SinglePixelPackedSampleModel; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; + +public class GIFImageReader extends ImageReader +{ + private GIFFile file; + + protected GIFImageReader(ImageReaderSpi originatingProvider) + { + super( originatingProvider ); + file = null; + } + + private void readImage() throws IOException + { + if( file != null ) + return; + + try + { + if( input instanceof InputStream ) + file = new GIFFile( (InputStream)input ); + else + file = new GIFFile( new IIOInputStream((ImageInputStream)input) ); + } + catch(GIFFile.GIFException ge) + { + throw new IIOException(ge.getMessage()); + } + } + + /** + * Returns the Global/Local palette as an IndexColorModel + */ + private IndexColorModel getPalette(int index) + { + GIFFile f = file.getImage( index ); + byte[] data = f.getRawPalette(); + int nc = f.getNColors(); + byte[] r = new byte[nc]; + byte[] g = new byte[nc]; + byte[] b = new byte[nc]; + + for(int i = 0; i < nc; i ++ ) + { + r[i] = data[ i * 3 ]; + g[i] = data[ i * 3 + 1 ]; + b[i] = data[ i * 3 + 2 ]; + } + + if( f.hasTransparency() ) + { + byte[] a = new byte[nc]; + for(int i = 0; i < nc; i ++ ) + a[i] = (byte)0xFF; + a[f.getTransparentIndex()] = 0; + return new IndexColorModel(8, nc, r, g, b, a); + } + + return new IndexColorModel(8, nc, r, g, b); + } + + private void validateIndex(int imageIndex) + throws IndexOutOfBoundsException + { + if( imageIndex < 0 || imageIndex >= getNumImages(false) ) + throw new IndexOutOfBoundsException("Invalid image index."); + } + + public void setInput(Object input) + { + super.setInput(input); + } + + public void setInput(Object input, + boolean seekForwardOnly, + boolean ignoreMetadata) + { + super.setInput(input, seekForwardOnly, ignoreMetadata); + } + + public void setInput(Object input, boolean isStreamable) + { + super.setInput(input, isStreamable); + + if (!(input instanceof ImageInputStream) && + !(input instanceof InputStream)) + throw new IllegalArgumentException("Input not an ImageInputStream."); + } + + private void checkStream() throws IOException + { + if (!(input instanceof ImageInputStream) && + !(input instanceof InputStream)) + throw new IllegalStateException("Input not an ImageInputStream or InputStream."); + + if(input == null) + throw new IllegalStateException("No input stream."); + } + + public int getWidth(int imageIndex) throws IOException + { + validateIndex( imageIndex ); + return file.getImage( imageIndex ).getWidth(); + } + + public int getHeight(int imageIndex) throws IOException + { + validateIndex( imageIndex ); + return file.getImage( imageIndex ).getHeight(); + } + + public Iterator getImageTypes(int imageIndex) + { + validateIndex( imageIndex ); + return null; + } + + /** + * Returns the number of images. + */ + public int getNumImages(boolean allowSearch) + { + try // Image should be loaded here already. But just in case: + { + readImage(); + } + catch(IOException ioe) + { + return 0; // Well, now we're in trouble. But return something anyway. + } + return file.nImages(); + } + + + // FIXME: Support metadata + public IIOMetadata getImageMetadata(int imageIndex) + { + validateIndex( imageIndex ); + return null; + } + + // FIXME: Support metadata + public IIOMetadata getStreamMetadata() + { + return null; + } + + /** + * Reads the image indexed by imageIndex and returns it as + * a complete BufferedImage, using a supplied ImageReadParam. + */ + public BufferedImage read(int imageIndex, ImageReadParam param) + throws IOException, IIOException + { + validateIndex( imageIndex ); + GIFFile f = file.getImage( imageIndex ); + int width = f.getWidth(); + int height = f.getHeight(); + SampleModel sm; + switch( f.getNColors() ) + { + case 16: + sm = new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, + width, height, 4); + break; + case 4: + sm = new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, + width, height, 2); + break; + case 2: + sm = new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, + width, height, 1); + break; + default: + sm = new SinglePixelPackedSampleModel(DataBuffer.TYPE_BYTE, + width, height, + new int[] {0xFF}); + break; + } + DataBuffer db = new DataBufferByte(f.getRawImage(), width * height, 0); + WritableRaster raster = Raster.createWritableRaster(sm, db, null); + + return new BufferedImage(getPalette( imageIndex ), raster, false, null); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/gif/GIFImageReaderSpi.java b/libjava/classpath/gnu/javax/imageio/gif/GIFImageReaderSpi.java new file mode 100644 index 000000000..285ca42e4 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/gif/GIFImageReaderSpi.java @@ -0,0 +1,124 @@ +/* GIFImageReaderSpi.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.gif; + +import gnu.javax.imageio.IIOInputStream; + +import java.io.InputStream; +import java.io.IOException; +import java.util.Locale; +import javax.imageio.ImageReader; +import javax.imageio.spi.ImageReaderSpi; +import javax.imageio.stream.ImageInputStream; + +public class GIFImageReaderSpi extends ImageReaderSpi +{ + static final String vendorName = "GNU"; + static final String version = "0.1"; + static final String readerClassName = + "gnu.javax.imageio.gif.GIFImageReader"; + static final String[] names = { "Compuserve GIF" }; + static final String[] suffixes = { ".gif" }; + static final String[] MIMETypes = { + "image/gif", + "image/x-gif"}; // Not sure this is legal, but it seems to be used a bit + static final String[] writerSpiNames = null; + static final boolean supportsStandardStreamMetadataFormat = false; + static final String nativeStreamMetadataFormatName = null; + static final String nativeStreamMetadataFormatClassName = null; + static final String[] extraStreamMetadataFormatNames = null; + static final String[] extraStreamMetadataFormatClassNames = null; + static final boolean supportsStandardImageMetadataFormat = false; + static final String nativeImageMetadataFormatName = null; + static final String nativeImageMetadataFormatClassName = null; + static final String[] extraImageMetadataFormatNames = null; + static final String[] extraImageMetadataFormatClassNames = null; + + public GIFImageReaderSpi() + { + super(vendorName, version, + names, suffixes, MIMETypes, + readerClassName, + new Class[]{ ImageInputStream.class, InputStream.class }, + writerSpiNames, + supportsStandardStreamMetadataFormat, + nativeStreamMetadataFormatName, + nativeStreamMetadataFormatClassName, + extraStreamMetadataFormatNames, + extraStreamMetadataFormatClassNames, + supportsStandardImageMetadataFormat, + nativeImageMetadataFormatName, + nativeImageMetadataFormatClassName, + extraImageMetadataFormatNames, + extraImageMetadataFormatClassNames); + } + + public String getDescription(Locale locale) + { + return "Compuserve GIF"; + } + + public boolean canDecodeInput(Object input) + throws IOException + { + if( input == null ) + throw new IllegalArgumentException("Input object cannot be null."); + + if( !(input instanceof ImageInputStream) && + !(input instanceof InputStream)) + return false; + + boolean retval; + InputStream in; + if( input instanceof ImageInputStream ) + in = new IIOInputStream( (ImageInputStream)input ); + else + in = (InputStream)input; + + in.mark(10); // we read 6 bytes + retval = GIFFile.readSignature( in ); + in.reset(); + + return retval; + } + + public ImageReader createReaderInstance(Object extension) + { + return new GIFImageReader(this); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/DCT.java b/libjava/classpath/gnu/javax/imageio/jpeg/DCT.java new file mode 100644 index 000000000..fda52e5f5 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/DCT.java @@ -0,0 +1,347 @@ +/* DCT.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +/** + * Discrete Cosine Transformations. + */ +public class DCT +{ + + /** + * Cosine matrix + */ + public double c[][] = new double[8][8]; + + /** + * Transformed cosine matrix + */ + public double cT[][] = new double[8][8]; + + public DCT() + { + initMatrix(); + } + + /** + * Figure A.3.3 IDCT, Cu Cv on A-5 of the ISO DIS 10918-1. Requirements and + * Guidelines. + * + * @param u + * @return + */ + public static double C(int u) + { + return ((u == 0) ? (double) 1 / (double) Math.sqrt((double) 2) + : (double) 1); + } + + /** + * Initialize matrix values for the fast_idct function + */ + private void initMatrix() + { + for (int j = 0; j < 8; j++) + { + double nn = (double) (8); + c[0][j] = 1.0 / Math.sqrt(nn); + cT[j][0] = c[0][j]; + } + for (int i = 1; i < 8; i++) + { + for (int j = 0; j < 8; j++) + { + double jj = (double) j; + double ii = (double) i; + c[i][j] = + Math.sqrt(2.0 / 8.0) + * Math.cos(((2.0 * jj + 1.0) * ii * Math.PI) / (2.0 * 8.0)); + cT[j][i] = c[i][j]; + } + } + } + + /** + * slow_idct - Figure A.3.3 IDCT (informative) on A-5 of the ISO DIS + * 10918-1. Requirements and Guidelines. This is a slow IDCT, there are + * better algorithms to use, it's fairly expensive with processor speed. + * + * @param matrix + * @return + */ + public static double[][] slow_idct(double[][] matrix) + { + double[][] output = new double[matrix.length][matrix.length]; + for (int y = 0; y < 8; y++) + { + for (int x = 0; x < 8; x++) + { + double val = 0; + for (double v = 0; v < 8; v++) + { + double innerloop = 0; + for (double u = 0; u < 8; u++) + innerloop += (DCT.C((int) u) / (double) 2) + * matrix[(int) v][(int) u] + * Math.cos((2 * x + 1) * u * Math.PI / (double) 16) + * Math.cos((2 * y + 1) * v * Math.PI / (double) 16); + val += (DCT.C((int) v) / (double) 2) * innerloop; + } + output[y][x] = (val + 128); + } + } + return (output); + } + + public static float[][] slow_fdct(float[][] value) + { + float[][] buffer = new float[8][8]; + + for (int u = 0; u < 8; u++) + { + for (int v = 0; v < 8; v++) + { + buffer[u][v] = + (float) (1 / 4) * (float) C((int) u) * (float) C((int) v); + float innerval = 0; + for (int x = 0; x < 8; x++) + { + for (int y = 0; y < 8; y++) + { + innerval += value[y][x] + * Math.cos(((2 * x + 1) * u * Math.PI) / 16) + * Math.cos(((2 * y + 1) * v * Math.PI) / 16); + } + } + buffer[u][v] *= innerval; + } + } + return (buffer); + } + + public float[][] fast_fdct(float[][] input) + { + float output[][] = new float[8][8]; + double temp[][] = new double[8][8]; + double temp1; + int i; + int j; + int k; + + for (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + { + temp[i][j] = 0.0; + for (k = 0; k < 8; k++) + { + temp[i][j] += (((int) (input[i][k]) - 128) * cT[k][j]); + } + } + } + + for (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + { + temp1 = 0.0; + + for (k = 0; k < 8; k++) + { + temp1 += (c[i][k] * temp[k][j]); + } + + output[i][j] = (int) Math.round(temp1) * 8; + } + } + + return output; + } + + /** + * fast_idct - Figure A.3.3 IDCT (informative) on A-5 of the ISO DIS + * 10918-1. Requires and Guidelines. This is a fast IDCT, it much more + * effecient and only inaccurate at about 1/1000th of a percent of values + * analyzed. Cannot be static because initMatrix must run before any + * fast_idct values can be computed. + * + * @param input + * @return + */ + public double[][] fast_idct(double[][] input) + { + double output[][] = new double[8][8]; + double temp[][] = new double[8][8]; + double temp1; + int i, j, k; + for (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + { + temp[i][j] = 0.0; + for (k = 0; k < 8; k++) + { + temp[i][j] += input[i][k] * c[k][j]; + } + } + } + for (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + { + temp1 = 0.0; + for (k = 0; k < 8; k++) + temp1 += cT[i][k] * temp[k][j]; + temp1 += 128.0; + if (temp1 < 0) + output[i][j] = 0; + else if (temp1 > 255) + output[i][j] = 255; + else + output[i][j] = (int) Math.round(temp1); + } + } + return output; + } + + public double[][] idj_fast_fdct(float input[][]) + { + double output[][] = new double[8][8]; + double tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + double tmp10, tmp11, tmp12, tmp13; + double z1, z2, z3, z4, z5, z11, z13; + int i; + int j; + + // Subtracts 128 from the input values + for (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + { + output[i][j] = ((double) input[i][j] - (double) 128.0); + // input[i][j] -= 128; + + } + } + + for (i = 0; i < 8; i++) + { + tmp0 = output[i][0] + output[i][7]; + tmp7 = output[i][0] - output[i][7]; + tmp1 = output[i][1] + output[i][6]; + tmp6 = output[i][1] - output[i][6]; + tmp2 = output[i][2] + output[i][5]; + tmp5 = output[i][2] - output[i][5]; + tmp3 = output[i][3] + output[i][4]; + tmp4 = output[i][3] - output[i][4]; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + output[i][0] = tmp10 + tmp11; + output[i][4] = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * (double) 0.707106781; + output[i][2] = tmp13 + z1; + output[i][6] = tmp13 - z1; + + tmp10 = tmp4 + tmp5; + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + z5 = (tmp10 - tmp12) * (double) 0.382683433; + z2 = ((double) 0.541196100) * tmp10 + z5; + z4 = ((double) 1.306562965) * tmp12 + z5; + z3 = tmp11 * ((double) 0.707106781); + + z11 = tmp7 + z3; + z13 = tmp7 - z3; + + output[i][5] = z13 + z2; + output[i][3] = z13 - z2; + output[i][1] = z11 + z4; + output[i][7] = z11 - z4; + } + + for (i = 0; i < 8; i++) + { + tmp0 = output[0][i] + output[7][i]; + tmp7 = output[0][i] - output[7][i]; + tmp1 = output[1][i] + output[6][i]; + tmp6 = output[1][i] - output[6][i]; + tmp2 = output[2][i] + output[5][i]; + tmp5 = output[2][i] - output[5][i]; + tmp3 = output[3][i] + output[4][i]; + tmp4 = output[3][i] - output[4][i]; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + output[0][i] = tmp10 + tmp11; + output[4][i] = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * (double) 0.707106781; + output[2][i] = tmp13 + z1; + output[6][i] = tmp13 - z1; + + tmp10 = tmp4 + tmp5; + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + z5 = (tmp10 - tmp12) * (double) 0.382683433; + z2 = ((double) 0.541196100) * tmp10 + z5; + z4 = ((double) 1.306562965) * tmp12 + z5; + z3 = tmp11 * ((double) 0.707106781); + + z11 = tmp7 + z3; + z13 = tmp7 - z3; + + output[5][i] = z13 + z2; + output[3][i] = z13 - z2; + output[1][i] = z11 + z4; + output[7][i] = z11 - z4; + } + + return output; + } + +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/HuffmanTable.java b/libjava/classpath/gnu/javax/imageio/jpeg/HuffmanTable.java new file mode 100644 index 000000000..78f3c1c4f --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/HuffmanTable.java @@ -0,0 +1,207 @@ +/* HuffmanTable.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +import java.io.IOException; + +import javax.imageio.plugins.jpeg.JPEGHuffmanTable; + + +/** + * This Object construct a JPEGHuffmanTable which can be used to encode/decode + * a scan from a JPEG codec stream. The table must be initalized with either a + * BITS byte amount and a Huffman Table Value for decoding or a Huffman Size + * and Huffman Code table for encoding. + */ +public class HuffmanTable +{ + public final static int HUFFMAN_MAX_TABLES = 4; + + private short[] huffcode = new short[256]; + private short[] huffsize = new short[256]; + private short[] EHUFCO; + private short[] EHUFSI; + private short[] valptr = new short[16]; + private short[] mincode = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1,-1,-1}; + private short[] maxcode = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}; + private short[] huffval; + private short[] bits; + + static byte JPEG_DC_TABLE = 0; + static byte JPEG_AC_TABLE = 1; + + private short lastk = 0; + + public HuffmanTable(JPEGHuffmanTable table) + { + huffcode = table.getValues(); + bits = table.getLengths(); + } + + /** + * Generated from FIGURE C.1 - Generation of table of Huffman code sizes on + * ISO DIS 10918-1. Requirements and Guidelines + */ + private void generateSizeTable() + { + short index=0; + for(short i=0; i < bits.length ; i++) + { + for(short j=0; j < bits[i] ; j++) + { + huffsize[index] = (short) (i+1); + index++; + } + } + lastk = index; + } + + /** + * Generated from FIGURE C.2 - Generation of table of Huffman codes on + * ISO DIS 10918-1. Requirements and Guidelines + */ + private void generateCodeTable() + { + short k=0; + short si = huffsize[0]; + short code = 0; + for(short i=0; i < huffsize.length ; i++) + { + while(huffsize[k]==si) + { + huffcode[k] = code; + code++; + k++; + } + code <<= 1; + si++; + } + } + + /** + * Generated from FIGURE F.15 - Generation of decode table generation on + * ISO DIS 10918-1. Requirements and Guidelines + */ + private void generateDecoderTables() + { + short bitcount = 0; + for(int i=0; i < 16 ; i++) + { + if(bits[i]!=0) + valptr[i] = bitcount; + for(int j=0 ; j < bits[i] ; j++) + { + if(huffcode[j+bitcount] < mincode[i] || mincode[i] == -1) + mincode[i] = huffcode[j+bitcount]; + + if(huffcode[j+bitcount] > maxcode[i]) + maxcode[i] = huffcode[j+bitcount]; + } + if(mincode[i]!=-1) + valptr[i] = (short) (valptr[i] - mincode[i]); + bitcount += bits[i]; + } + } + + /** + * Generated from FIGURE C.3 - Generation of Order Codes and tables EHUFCO + * and EHUFSI from the ISO DIS 10918-1. Requirements and Guidelines + */ + public void orderCodes(boolean isDC) + { + EHUFCO = new short[isDC ? 15 : 255]; + EHUFSI = new short[isDC ? 15 : 255]; + + for (int p=0; p < lastk ; p++) + { + int i = huffval[p]; + if(i < 0 || i > EHUFCO.length || EHUFSI[i]!=0) + System.err.println("Error, bad huffman table."); + EHUFCO[i] = huffcode[p]; + EHUFSI[i] = huffsize[p]; + } + } + + /** + * Generated from FIGURE F.12 - Extending the sign bit of a decoded value in on + * ISO DIS 10918-1. Requirements and Guidelines

+ * + * @param diff TODO + * @param t TODO + * @return TODO + */ + public static int extend(int diff, int t) + { + int Vt = (int)Math.pow(2,(t-1)); + if(diff + * + * This function takes in a dynamic amount of bits and using the Huffman + * table returns information on how many bits must be read in to a byte in + * order to reconstruct said byte. + * + * @param JPEGStream the bits of the data stream. + */ + public int decode(JPEGImageInputStream JPEGStream) + throws IOException, JPEGException + { + int i=0; + short code = (short) JPEGStream.readBits(1); + while(code > maxcode[i]) + { + i++; + code <<= 1; + code |= JPEGStream.readBits(1); + } + int val = huffval[code+(valptr[i])]; + if(val < 0) + val = 256 + val; + return val; + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/JPEGComponent.java b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGComponent.java new file mode 100644 index 000000000..7be67a02a --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGComponent.java @@ -0,0 +1,351 @@ +/* JPEGComponent.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +import java.util.ArrayList; +import java.io.IOException; +import java.awt.image.WritableRaster; + +import javax.imageio.plugins.jpeg.JPEGHuffmanTable; + +/** + * This class holds the methods to decode and write a component information to + * a raster. + */ +public class JPEGComponent +{ + public byte factorH, factorV, component_id, quant_id; + public int width = 0, height = 0, maxV = 0, maxH = 0; + public HuffmanTable ACTable; + public HuffmanTable DCTable; + public int[] quantizationTable; + public double previousDC = 0; + ArrayList data = new ArrayList(); + + /** + * Initializes the component + * + * @param id + * @param factorHorizontal + * @param factorVertical + * @param quantizationID + */ + public JPEGComponent(byte id, byte factorHorizontal, byte factorVertical, + byte quantizationID) + { + component_id = id; + factorH = factorHorizontal; + factorV = factorVertical; + quant_id = quantizationID; + } + + /** + * If a restart marker is found with too little of an MCU count (i.e. our + * Restart Interval is 63 and we have 61 we copy the last MCU until it's + * full) + * + * @param index + * @param length + */ + public void padMCU(int index, int length) + { + double[] src = (double[]) data.get(index - 1); + for (int i = 0; i < length; i++) + data.add(index, src); + } + + /** + * Reset the interval by setting the previous DC value + */ + public void resetInterval() + { + previousDC = 0; + } + + /** + * Run the Quantization backward method on all of the block data. + */ + public void quantitizeData() + { + for (int i = 0; i < data.size(); i++) + { + double[] mydata = (double[]) data.get(i); + for (int j = 0; j < mydata.length; j++) + mydata[j] *= quantizationTable[j]; + } + } + + public void setDCTable(JPEGHuffmanTable table) + { + DCTable = new HuffmanTable(table); + } + + public void setACTable(JPEGHuffmanTable table) + { + ACTable = new HuffmanTable(table); + } + + /** + * Run the Inverse DCT method on all of the block data + */ + public void idctData(DCT myDCT) + { + for (int i = 0; i < data.size(); i++) + data.add(i,myDCT.fast_idct(ZigZag.decode8x8_map((double[]) data.remove(i)))); + } + + /** + * This scales up the component size based on the factor size. This + * calculates everyting up automatically so it's simply ran at the end of + * the frame to normalize the size of all of the components. + */ + public void scaleByFactors() + { + int factorUpVertical = maxV / factorV; + int factorUpHorizontal = maxH / factorH; + + if (factorUpVertical > 1) + { + for (int i = 0; i < data.size(); i++) + { + double[][] src = (double[][]) data.remove(i); + double[][] dest = + new double[src.length * factorUpVertical][src[0].length]; + for (int j = 0; j < src.length; j++) + { + for (int u = 0; u < factorUpVertical; u++) + { + dest[j * factorUpVertical + u] = src[j]; + } + } + data.add(i, dest); + } + } + + if (factorUpHorizontal > 1) + { + for (int i = 0; i < data.size(); i++) + { + double[][] src = (double[][]) data.remove(i); + double[][] dest = + new double[src.length][src[0].length * factorUpHorizontal]; + for (int j = 0; j < src.length; j++) + { + for (int u = 0; u < src[0].length; u++) + { + for (int v = 0; v < factorUpHorizontal; v++) + dest[j][u * factorUpHorizontal + v] = src[j][u]; + } + } + data.add(i, dest); + } + } + } + + /** + * This write the block of data to the raster throwing out anything that + * spills over the raster width or height. + * + * @param raster + * @param data + * @param compIndex + * @param x + * @param y + */ + public void writeBlock(WritableRaster raster, double[][] data, + int compIndex, int x, int y) + { + for (int yIndex = 0; yIndex < data.length; yIndex++) + { + for (int xIndex = 0; xIndex < data[yIndex].length; xIndex++) + { + // The if statement is needed because blocks can spill over the + // frame width because they are padded to make sure we keep the + // height of the block the same as the width of the block + if (x + xIndex < raster.getWidth() + && y + yIndex < raster.getHeight()) + raster.setSample(x + xIndex, y + yIndex, compIndex, + data[yIndex][xIndex]); + } + } + } + + /** + * This writes data to a raster block, so really it's reading not writing + * but it writes the data to the raster block by factor size in a zig zag + * fashion. This has the helper function writeBlock which does the actual + * writing. + * + * @param raster + * @param componentIndex + */ + public void writeData(WritableRaster raster, int componentIndex) + { + int x = 0, y = 0, lastblockheight = 0, incrementblock = 0; + + // Keep looping through all of the blocks until there are no more. + while(data.size() > 0) + { + int blockwidth = 0; + int blockheight = 0; + + if (x >= raster.getWidth()) + { + x = 0; + y += incrementblock; + } + + // Loop through the horizontal component blocks of the MCU first + // then for each horizontal line write out all of the vertical + // components + for (int factorVIndex = 0; factorVIndex < factorV; factorVIndex++) + { + blockwidth = 0; + + for (int factorHIndex = 0; factorHIndex < factorH; factorHIndex++) + { + // Captures the width of this block so we can increment the + // X coordinate + double[][] blockdata = (double[][]) data.remove(0); + + // Writes the data at the specific X and Y coordinate of + // this component + writeBlock(raster, blockdata, componentIndex, x, y); + blockwidth += blockdata[0].length; + x += blockdata[0].length; + blockheight = blockdata.length; + } + y += blockheight; + x -= blockwidth; + lastblockheight += blockheight; + } + y -= lastblockheight; + incrementblock = lastblockheight; + lastblockheight = 0; + x += blockwidth; + } + } + + /** + * Set the quantization table for this component. + * + * @param quanttable + */ + public void setQuantizationTable(int[] quanttable) + { + quantizationTable = quanttable; + } + + /** + * Read in a partial MCU for this component + * + * @param stream TODO + * @throws JPEGException TODO + * @throws IOException TODO + */ + public void readComponentMCU(JPEGImageInputStream stream) + throws JPEGException, IOException + { + for (int i = 0; i < factorH * factorV; i++) + { + double dc = decode_dc_coefficient(stream); + double[] datablock = decode_ac_coefficients(stream); + datablock[0] = dc; + data.add(datablock); + } + } + + /** + * Generated from text on F-22, F.2.2.1 - Huffman decoding of DC + * coefficients on ISO DIS 10918-1. Requirements and Guidelines. + * + * @param JPEGStream TODO + * + * @return TODO + * @throws JPEGException TODO + * @throws IOException TODO + */ + public double decode_dc_coefficient(JPEGImageInputStream JPEGStream) + throws JPEGException, IOException + { + int t = DCTable.decode(JPEGStream); + double diff = JPEGStream.readBits(t); + diff = HuffmanTable.extend((int) diff, t); + diff = (previousDC + diff); + previousDC = diff; + return diff; + } + + /** + * Generated from text on F-23, F.13 - Huffman decoded of AC coefficients + * on ISO DIS 10918-1. Requirements and Guidelines. + * + * @param JPEGStream TODO + * @return TODO + * + * @throws JPEGException TODO + * @throws IOException TODO + */ + public double[] decode_ac_coefficients(JPEGImageInputStream JPEGStream) + throws JPEGException, IOException + { + double[] zz = new double[64]; + + for (int k = 1; k < 64; k++) + { + int s = ACTable.decode(JPEGStream); + int r = s >> 4; + s &= 15; + + if (s != 0) + { + k += r; + r = (int) JPEGStream.readBits(s); + s = HuffmanTable.extend(r, s); + zz[k] = s; + } + else + { + if (r != 15) + return (zz); + k += 15; + } + } + return zz; + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/JPEGDecoder.java b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGDecoder.java new file mode 100644 index 000000000..11d547f4d --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGDecoder.java @@ -0,0 +1,625 @@ +/* JPEGDecoder.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +import java.io.IOException; +import java.nio.ByteOrder; + +import javax.imageio.plugins.jpeg.JPEGHuffmanTable; +import javax.imageio.plugins.jpeg.JPEGQTable; +import javax.imageio.stream.ImageInputStream; + +import java.util.ArrayList; +import java.util.Hashtable; +import java.awt.Point; +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.awt.image.BufferedImage; +import java.awt.image.ComponentColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; + +public class JPEGDecoder +{ + byte majorVersion; + byte minorVersion; + byte units; + short Xdensity; + short Ydensity; + byte Xthumbnail; + byte Ythumbnail; + byte[] thumbnail; + BufferedImage image; + int width; + int height; + + byte marker; + + /** + * This decoder expects JFIF 1.02 encoding. + */ + public static final byte MAJOR_VERSION = (byte) 1; + public static final byte MINOR_VERSION = (byte) 2; + + /** + * The length of the JFIF field not including thumbnail data. + */ + public static final short JFIF_FIXED_LENGTH = 16; + + /** + * The length of the JFIF extension field not including extension + * data. + */ + public static final short JFXX_FIXED_LENGTH = 8; + + private JPEGImageInputStream jpegStream; + + ArrayList jpegFrames = new ArrayList(); + + JPEGHuffmanTable[] dcTables = new JPEGHuffmanTable[4]; + JPEGHuffmanTable[] acTables = new JPEGHuffmanTable[4]; + JPEGQTable[] qTables = new JPEGQTable[4]; + + public int getHeight() + { + return height; + } + + public int getWidth() + { + return width; + } + public JPEGDecoder(ImageInputStream in) + throws IOException, JPEGException + { + jpegStream = new JPEGImageInputStream(in); + jpegStream.setByteOrder(ByteOrder.LITTLE_ENDIAN); + + if (jpegStream.findNextMarker() != JPEGMarker.SOI) + throw new JPEGException("Failed to find SOI marker."); + + if (jpegStream.findNextMarker() != JPEGMarker.APP0) + throw new JPEGException("Failed to find APP0 marker."); + + int length = jpegStream.readShort(); + if (!(length >= JFIF_FIXED_LENGTH)) + throw new JPEGException("Failed to find JFIF field."); + + byte[] identifier = new byte[5]; + jpegStream.read(identifier); + if (identifier[0] != JPEGMarker.JFIF_J + || identifier[1] != JPEGMarker.JFIF_F + || identifier[2] != JPEGMarker.JFIF_I + || identifier[3] != JPEGMarker.JFIF_F + || identifier[4] != JPEGMarker.X00) + throw new JPEGException("Failed to read JFIF identifier."); + + majorVersion = jpegStream.readByte(); + minorVersion = jpegStream.readByte(); + if (majorVersion != MAJOR_VERSION + || (majorVersion == MAJOR_VERSION + && minorVersion < MINOR_VERSION)) + throw new JPEGException("Unsupported JFIF version."); + + units = jpegStream.readByte(); + if (units > (byte) 2) + throw new JPEGException("Units field is out of range."); + + Xdensity = jpegStream.readShort(); + Ydensity = jpegStream.readShort(); + Xthumbnail = jpegStream.readByte(); + Ythumbnail = jpegStream.readByte(); + + // 3 * for RGB data + int thumbnailLength = 3 * Xthumbnail * Ythumbnail; + if (length > JFIF_FIXED_LENGTH + && thumbnailLength != length - JFIF_FIXED_LENGTH) + throw new JPEGException("Invalid length, Xthumbnail" + + " or Ythumbnail field."); + + if (thumbnailLength > 0) + { + thumbnail = new byte[thumbnailLength]; + if (jpegStream.read(thumbnail) != thumbnailLength) + throw new IOException("Failed to read thumbnail."); + } + } + + public void decode() + throws IOException + { + System.out.println ("DECODE!!!"); + // The frames in this jpeg are loaded into a list. There is + // usually just one frame except in heirarchial progression where + // there are multiple frames. + JPEGFrame frame = null; + + // The restart interval defines how many MCU's we should have + // between the 8-modulo restart marker. The restart markers allow + // us to tell whether or not our decoding process is working + // correctly, also if there is corruption in the image we can + // recover with these restart intervals. (See RSTm DRI). + int resetInterval = 0; + + // The JPEGDecoder constructor parses the JFIF field. At this + // point jpegStream points to the first byte after the JFIF field. + + // Find the first marker after the JFIF field. + byte marker = jpegStream.findNextMarker(); + + // Check for a JFIF extension field directly following the JFIF + // header and advance the current marker to the next marker in the + // stream, if necessary. + decodeJFIFExtension(); + + // Loop through until there are no more markers to read in, at + // that point everything is loaded into the jpegFrames array and + // can be processed. + while (true) + { + switch (marker) + { + // APPn Application Reserved Information - Just throw this + // information away because we wont be using it. + case JPEGMarker.APP0: + case JPEGMarker.APP1: + case JPEGMarker.APP2: + case JPEGMarker.APP3: + case JPEGMarker.APP4: + case JPEGMarker.APP5: + case JPEGMarker.APP6: + case JPEGMarker.APP7: + case JPEGMarker.APP8: + case JPEGMarker.APP9: + case JPEGMarker.APP10: + case JPEGMarker.APP11: + case JPEGMarker.APP12: + case JPEGMarker.APP13: + case JPEGMarker.APP14: + case JPEGMarker.APP15: + jpegStream.skipBytes(jpegStream.readShort() - 2); + break; + + case JPEGMarker.SOF0: + // SOFn Start of Frame Marker, Baseline DCT - This is the start + // of the frame header that defines certain variables that will + // be carried out through the rest of the encoding. Multiple + // frames are used in a heirarchiel system, however most JPEG's + // only contain a single frame. + jpegFrames.add(new JPEGFrame()); + frame = (JPEGFrame) jpegFrames.get(jpegFrames.size() - 1); + // Skip the frame length. + jpegStream.readShort(); + // Bits percision, either 8 or 12. + frame.setPrecision(jpegStream.readByte()); + // Scan lines = to the height of the frame. + frame.setScanLines(jpegStream.readShort()); + // Scan samples per line = to the width of the frame. + frame.setSamplesPerLine(jpegStream.readShort()); + // Number of Color Components (or channels). + frame.setComponentCount(jpegStream.readByte()); + + // Set the color mode for this frame, so far only 2 color + // modes are supported. + if (frame.getComponentCount() == 1) + frame.setColorMode(JPEGFrame.JPEG_COLOR_GRAY); + else + frame.setColorMode(JPEGFrame.JPEG_COLOR_YCbCr); + // Add all of the necessary components to the frame. + for (int i = 0; i < frame.getComponentCount(); i++) + frame.addComponent(jpegStream.readByte(), jpegStream.readByte(), + jpegStream.readByte()); + break; + + case JPEGMarker.SOF2: + jpegFrames.add(new JPEGFrame()); + frame = (JPEGFrame) jpegFrames.get(jpegFrames.size() - 1); + // Skip the frame length. + jpegStream.readShort(); + // Bits percision, either 8 or 12. + frame.setPrecision(jpegStream.readByte()); + // Scan lines = to the height of the frame. + frame.setScanLines(jpegStream.readShort()); + // Scan samples per line = to the width of the frame. + frame.setSamplesPerLine(jpegStream.readShort()); + // Number of Color Components (or channels). + frame.setComponentCount(jpegStream.readByte()); + + // Set the color mode for this frame, so far only 2 color + // modes are supported. + if (frame.getComponentCount() == 1) + frame.setColorMode(JPEGFrame.JPEG_COLOR_GRAY); + else + frame.setColorMode(JPEGFrame.JPEG_COLOR_YCbCr); + + // Add all of the necessary components to the frame. + for (int i = 0; i < frame.getComponentCount(); i++) + frame.addComponent(jpegStream.readByte(), jpegStream.readByte(), + jpegStream.readByte()); + break; + + case JPEGMarker.DHT: + // DHT non-SOF Marker - Huffman Table is required for decoding + // the JPEG stream, when we receive a marker we load in first + // the table length (16 bits), the table class (4 bits), table + // identifier (4 bits), then we load in 16 bytes and each byte + // represents the count of bytes to load in for each of the 16 + // bytes. We load this into an array to use later and move on 4 + // huffman tables can only be used in an image. + int huffmanLength = (jpegStream.readShort() - 2); + + // Keep looping until we are out of length. + int index = huffmanLength; + + // Multiple tables may be defined within a DHT marker. This + // will keep reading until there are no tables left, most + // of the time there are just one tables. + while (index > 0) + { + // Read the identifier information and class + // information about the Huffman table, then read the + // 16 byte codelength in and read in the Huffman values + // and put it into table info. + byte huffmanInfo = jpegStream.readByte(); + byte tableClass = (byte) (huffmanInfo >> 4); + byte huffmanIndex = (byte) (huffmanInfo & 0x0f); + short[] codeLength = new short[16]; + jpegStream.readFully(codeLength, 0, codeLength.length); + int huffmanValueLen = 0; + for (int i = 0; i < 16; i++) + huffmanValueLen += codeLength[i]; + index -= (huffmanValueLen + 17); + short[] huffmanVal = new short[huffmanValueLen]; + for (int i = 0; i < huffmanVal.length; i++) + huffmanVal[i] = jpegStream.readByte(); + // Assign DC Huffman Table. + if (tableClass == HuffmanTable.JPEG_DC_TABLE) + dcTables[(int) huffmanIndex] = new JPEGHuffmanTable(codeLength, + huffmanVal); + // Assign AC Huffman Table. + else if (tableClass == HuffmanTable.JPEG_AC_TABLE) + acTables[(int) huffmanIndex] = new JPEGHuffmanTable(codeLength, + huffmanVal); + } + break; + case JPEGMarker.DQT: + // DQT non-SOF Marker - This defines the quantization + // coeffecients, this allows us to figure out the quality of + // compression and unencode the data. The data is loaded and + // then stored in to an array. + short quantizationLength = (short) (jpegStream.readShort() - 2); + for (int j = 0; j < quantizationLength / 65; j++) + { + byte quantSpecs = jpegStream.readByte(); + int[] quantData = new int[64]; + if ((byte) (quantSpecs >> 4) == 0) + // Precision 8 bit. + { + for (int i = 0; i < 64; i++) + quantData[i] = jpegStream.readByte(); + + } + else if ((byte) (quantSpecs >> 4) == 1) + // Precision 16 bit. + { + for (int i = 0; i < 64; i++) + quantData[i] = jpegStream.readShort(); + } + qTables[(int) (quantSpecs & 0x0f)] = new JPEGQTable (quantData); + } + break; + case JPEGMarker.SOS: + // SOS non-SOF Marker - Start Of Scan Marker, this is where the + // actual data is stored in a interlaced or non-interlaced with + // from 1-4 components of color data, if three components most + // likely a YCrCb model, this is a fairly complex process. + + // Read in the scan length. + jpegStream.readShort(); + // Number of components in the scan. + byte numberOfComponents = jpegStream.readByte(); + byte[] componentSelector = new byte[numberOfComponents]; + for (int i = 0; i < numberOfComponents; i++) + { + // Component ID, packed byte containing the Id for the + // AC table and DC table. + byte componentID = jpegStream.readByte(); + byte tableInfo = jpegStream.readByte(); + frame.setHuffmanTables(componentID, + acTables[(byte) (tableInfo >> 4)], + dcTables[(byte) (tableInfo & 0x0f)]); + componentSelector[i] = componentID; + } + byte startSpectralSelection = jpegStream.readByte(); + byte endSpectralSelection = jpegStream.readByte(); + byte successiveApproximation = jpegStream.readByte(); + + int mcuIndex = 0; + int mcuTotalIndex = 0; + // This loops through until a MarkerTagFound exception is + // found, if the marker tag is a RST (Restart Marker) it + // simply skips it and moves on this system does not handle + // corrupt data streams very well, it could be improved by + // handling misplaced restart markers. + while (true) + { + try + { + // Loop though capturing MCU, instruct each + // component to read in its necessary count, for + // scaling factors the components automatically + // read in how much they need + for (int compIndex = 0; compIndex < numberOfComponents; compIndex++) + { + JPEGComponent comp = frame.components.getComponentByID(componentSelector[compIndex]); + comp.readComponentMCU(jpegStream); + } + mcuIndex++; + mcuTotalIndex++; + } + // We've found a marker, see if the marker is a restart + // marker or just the next marker in the stream. If + // it's the next marker in the stream break out of the + // while loop, if it's just a restart marker skip it + catch (JPEGMarkerFoundException bse) + { + // Handle JPEG Restart Markers, this is where the + // count of MCU's per interval is compared with + // the count actually obtained, if it's short then + // pad on some MCU's ONLY for components that are + // greater than one. Also restart the DC prediction + // to zero. + if (marker == JPEGMarker.RST0 + || marker == JPEGMarker.RST1 + || marker == JPEGMarker.RST2 + || marker == JPEGMarker.RST3 + || marker == JPEGMarker.RST4 + || marker == JPEGMarker.RST5 + || marker == JPEGMarker.RST6 + || marker == JPEGMarker.RST7) + { + for (int compIndex = 0; compIndex < numberOfComponents; compIndex++) + { + JPEGComponent comp = frame.components.getComponentByID(componentSelector[compIndex]); + if (compIndex > 1) + comp.padMCU(mcuTotalIndex, resetInterval - mcuIndex); + comp.resetInterval(); + } + mcuTotalIndex += (resetInterval - mcuIndex); + mcuIndex = 0; + } + else + { + // We're at the end of our scan, exit out. + break; + } + } + } + break; + case JPEGMarker.DRI: + // DRI - This defines the restart interval, if we have a + // restart interval when we reach our restart modulo calculate + // whether the count of MCU's specified in the restart + // interval have been reached, if they havent then pad with + // whatever MCU was last used, this is supposed to be a form of + // error recovery but it turns out that some JPEG encoders + // purposely cause missing MCU's on repeating MCU's to compress + // data even more (even though it adds an extra layer of + // complexity.. But since when is JPEG easy? + jpegStream.skipBytes(2); + resetInterval = jpegStream.readShort(); + break; + case JPEGMarker.COM: + // COM - This is a comment that was inserted into the JPEG, we + // simply skip over the comment because it's really of no + // importance, usually contains a verbal description of the + // application or author who created the JPEG. + jpegStream.skipBytes(jpegStream.readShort() - 2); + break; + case JPEGMarker.DNL: + // DNL - This sets the height of the image. This is the Define + // Number Lines for the image, I'm not sure exactly why we need + // this but, whatever we'll abide. + frame.setScanLines(jpegStream.readShort()); + break; + case JPEGMarker.EOI: + // EOI - End of Image, this processes the frames and turns the + // frames into a buffered image. + + if (jpegFrames.size() == 0) + { + return; + } + else if (jpegFrames.size() == 1) + { + // Only one frame, JPEG Non-Heirarchial Frame. + + DCT myDCT = new DCT(); + WritableRaster raster = + Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, + frame.width, + frame.height, + frame.getComponentCount(), + new Point(0, 0)); + + // Unencode the data. + for (int i = 0; i < frame.getComponentCount(); i++) + { + JPEGComponent comp = frame.components.get(i); + comp.setQuantizationTable(qTables[comp.quant_id].getTable()); + comp.quantitizeData(); + comp.idctData(myDCT); + } + // Scale the image and write the data to the raster. + for (int i = 0; i < frame.getComponentCount(); i++) + { + JPEGComponent comp = frame.components.get(i); + comp.scaleByFactors(); + comp.writeData(raster, i); + // Ensure garbage collection. + comp = null; + } + // Grayscale Color Image (1 Component). + if (frame.getComponentCount() == 1) + { + ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY); + ComponentColorModel ccm = + new ComponentColorModel(cs, false, false, + Transparency.OPAQUE, + DataBuffer.TYPE_BYTE); + image = new BufferedImage(ccm, raster, false, + new Hashtable()); + } + // YCbCr Color Image (3 Components). + else if (frame.getComponentCount() == 3) + { + ComponentColorModel ccm = + new ComponentColorModel(new YCbCr_ColorSpace(), false, + false, Transparency.OPAQUE, + DataBuffer.TYPE_BYTE); + image = new BufferedImage(ccm, raster, false, + new Hashtable()); + } + // Possibly CMYK or RGBA ? + else + { + throw new JPEGException("Unsupported Color Mode: 4 " + + "Component Color Mode found."); + } + height = frame.height; + width = frame.width; + } + else + { + //JPEG Heirarchial Frame (progressive or baseline). + throw new JPEGException("Unsupported Codec Type:" + + " Hierarchial JPEG"); + } + break; + case JPEGMarker.SOF1: + // ERROR - If we encounter any of the following marker codes + // error out with a codec exception, progressive, heirarchial, + // differential, arithmetic, lossless JPEG's are not supported. + // This is where enhancements can be made for future versions. + // Thankfully 99% of all JPEG's are baseline DCT. + throw new JPEGException("Unsupported Codec Type: Extended " + + "Sequential DCT JPEG's Not-Supported"); + //case JPEGMarker.SOF2: + // throw new JPEGException("Unsupported Codec Type: Progressive DCT JPEG's Not-Supported"); + case JPEGMarker.SOF3: + throw new JPEGException("Unsupported Codec Type:" + + " Lossless (sequential)"); + case JPEGMarker.SOF5: + throw new JPEGException("Unsupported Codec Type:" + + " Differential sequential DCT"); + case JPEGMarker.SOF6: + throw new JPEGException("Unsupported Codec Type:" + + " Differential progressive DCT"); + case JPEGMarker.SOF7: + throw new JPEGException("Unsupported Codec Type:" + + " Differential lossless"); + case JPEGMarker.SOF9: + case JPEGMarker.SOF10: + case JPEGMarker.SOF11: + case JPEGMarker.SOF13: + case JPEGMarker.SOF14: + case JPEGMarker.SOF15: + throw new JPEGException("Unsupported Codec Type:" + + " Arithmetic Coding Frame"); + default: + // Unknown marker found, ignore it. + } + marker = jpegStream.findNextMarker(); + } + } + + // If the current marker is APP0, tries to decode a JFIF extension + // and advances the current marker to the next marker in the stream. + private void decodeJFIFExtension() throws IOException + { + if (marker == JPEGMarker.APP0) + { + int length = jpegStream.readShort(); + + if (length >= JFXX_FIXED_LENGTH) + { + byte[] identifier = new byte[5]; + jpegStream.read(identifier); + if (identifier[0] != JPEGMarker.JFIF_J + || identifier[1] != JPEGMarker.JFIF_F + || identifier[2] != JPEGMarker.JFIF_X + || identifier[3] != JPEGMarker.JFIF_X + || identifier[4] != JPEGMarker.X00) + // Not a JFXX field. Ignore it and continue. + jpegStream.skipBytes(length - 7); + else + { + byte extension_code = jpegStream.readByte(); + + switch (extension_code) + { + case JPEGMarker.JFXX_JPEG: + // FIXME: add support for JFIF Extension: + // Thumbnail coded using JPEG. + jpegStream.skipBytes(length - 8); + case JPEGMarker.JFXX_ONE_BPP: + // FIXME: add support for JFIF Extension: + // Thumbnail stored using 1 byte/pixel. + jpegStream.skipBytes(length - 8); + case JPEGMarker.JFXX_THREE_BPP: + // FIXME: add support for JFIF Extension: + // Thumbnail stored using 3 bytes/pixel. + jpegStream.skipBytes(length - 8); + } + } + } + else + { + // Unknown APP0 marker. Ignore it and continue. + jpegStream.skipBytes(length - 2); + } + marker = jpegStream.findNextMarker(); + } + } + + public BufferedImage getImage() + { + return image; + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/JPEGException.java b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGException.java new file mode 100644 index 000000000..a2c06e27e --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGException.java @@ -0,0 +1,48 @@ +/* JPEGException.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +import javax.imageio.*; + +public class JPEGException extends IIOException +{ + public JPEGException(String message) + { + super(message); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/JPEGFrame.java b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGFrame.java new file mode 100644 index 000000000..35aed728a --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGFrame.java @@ -0,0 +1,108 @@ +/* JPEGFrame.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +import javax.imageio.plugins.jpeg.JPEGHuffmanTable; + +public class JPEGFrame +{ + public final static byte JPEG_COLOR_GRAY = 1; + public final static byte JPEG_COLOR_RGB = 2; + public final static byte JPEG_COLOR_YCbCr = 3; + public final static byte JPEG_COLOR_CMYK = 4; + + public byte precision = 8; + public byte colorMode = JPEGFrame.JPEG_COLOR_YCbCr; + public byte componentCount = 0; + + public short width=0, height=0; + + public JPEGScan components; + + public JPEGFrame() + { + components = new JPEGScan(); + } + + public void addComponent(byte componentID, byte sampleFactors, + byte quantizationTableID) + { + byte sampleHorizontalFactor = (byte)(sampleFactors >> 4); + byte sampleVerticalFactor = (byte)(sampleFactors & 0x0f); + components.addComponent(componentID, sampleHorizontalFactor, + sampleVerticalFactor, quantizationTableID); + } + + public void setPrecision(byte data) + { + precision = data; + } + + public void setScanLines(short data) + { + height = data; + } + + public void setSamplesPerLine(short data) + { + width = data; + } + + public void setColorMode(byte data) + { + colorMode = data; + } + + public void setComponentCount(byte data) + { + componentCount = data; + } + + public byte getComponentCount() + { + return componentCount; + } + + public void setHuffmanTables(byte componentID, JPEGHuffmanTable ACTable, + JPEGHuffmanTable DCTable) + { + JPEGComponent comp = components.getComponentByID(componentID); + comp.setACTable(ACTable); + comp.setDCTable(DCTable); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageInputStream.java b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageInputStream.java new file mode 100644 index 000000000..f2c26d9d5 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageInputStream.java @@ -0,0 +1,188 @@ +/* JPEGImageInputStream.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +import java.io.IOException; +import javax.imageio.stream.ImageInputStream; +import javax.imageio.stream.ImageInputStreamImpl; + +public class JPEGImageInputStream + extends ImageInputStreamImpl +{ + private ImageInputStream in; + + byte marker; + + public JPEGImageInputStream(ImageInputStream in) + { + super(); + + this.in = in; + } + + public int read() + throws IOException + { + setBitOffset(0); + return in.read(); + } + + public int read(byte[] data, int offset, int len) + throws IOException + { + setBitOffset(0); + return in.read(data, offset, len); + } + + /** + * Pull a byte from the stream, this checks to see if the byte is 0xff + * and if the next byte isn't 0x00 (stuffed byte) it errors out. If it's + * 0x00 then it simply ignores the byte. + * + * @return the next byte in the buffer + * + * @throws IOException TODO + * @throws BitStreamException TODO + */ + private byte pullByte() throws IOException, JPEGMarkerFoundException + { + byte mybyte = readByte(); + // FIXME: handle multiple 0xff in a row + if(mybyte==(byte)(0xff)) + { + byte secondbyte = readByte(); + if(secondbyte != (byte)(0x00)) + { + marker = secondbyte; + throw new JPEGMarkerFoundException(); + } + } + return mybyte; + } + + /** + * This returns the marker that was last encountered. This should only be + * used if removeBit() throws a MarkerTagFound exception. + * + * @return marker as byte + */ + public byte getMarker() + { + return marker; + } + + /** + * Removes a bit from the buffer. (Removes from the top of a queue). This + * also checks for markers and throws MarkerTagFound exception if it does. + * If MarkerTagFound is thrown you can use getMarker() method to get the + * marker that caused the throw. + * + * @param l specifies how many bits you want to remove and add to the + * integer + * @return the amount of bits specified by l as an integer + * + * @throws IOException TODO + * @throws JPEGMarkerFoundException + * @throws BitStreamException TODO + */ + public int readBit() + throws IOException, JPEGMarkerFoundException +{ + checkClosed(); + + // Calc new bit offset here, readByte resets it. + int newOffset = (bitOffset + 1) & 0x7; + + byte data = pullByte(); + + if (bitOffset != 0) + { + seek(getStreamPosition() - 1); + data = (byte) (data >> (8 - newOffset)); + } + + bitOffset = newOffset; + return data & 0x1; +} + + + /** + * This method skips over the the data and finds the next position + * in the bit sequence with a X'FF' X'??' sequence. Multiple X'FF + * bytes in sequence are considered padding and interpreted as one + * X'FF byte. + * + * @return the next marker byte in the stream + * @throws IOException if the end of the stream is reached + * unexpectedly + */ + public byte findNextMarker() + throws IOException + { + boolean marked0xff = false; + byte byteinfo = JPEGMarker.X00; + + setBitOffset(0); + while (true) + { + byteinfo = readByte(); + if (!marked0xff) + { + if (byteinfo == JPEGMarker.XFF) + marked0xff = true; + } + else + { + if (byteinfo == JPEGMarker.XFF) + // Ignore the value 0xff when it is immediately + // followed by another 0xff byte. + continue; + else if (byteinfo == JPEGMarker.X00) + // The sequence 0xff 0x00 is used to encode the + // actual value 0xff. So restart our search for a + // marker. + marked0xff = false; + else + // One or more 0xff values were follwed by a + // non-0x00, non-0xff value so return this as the + // marker byte. + return byteinfo; + } + } + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageReader.java b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageReader.java new file mode 100644 index 000000000..5ecbe0f8c --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageReader.java @@ -0,0 +1,141 @@ +/* JPEGImageReader.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +import java.io.IOException; +import javax.imageio.*; +import javax.imageio.spi.*; +import javax.imageio.metadata.*; +import javax.imageio.stream.ImageInputStream; +import java.util.Iterator; +import java.awt.image.BufferedImage; + +public class JPEGImageReader extends ImageReader +{ + JPEGDecoder decoder; + + protected JPEGImageReader(ImageReaderSpi originatingProvider) + { + super(originatingProvider); + System.out.println("JPEGIMAGEREADER!!!"); + } + + // Abstract ImageReader methods. + public int getHeight(int imageIndex) + throws IOException + { + checkIndex(imageIndex); + decodeStream(); + return decoder.getHeight(); + } + + public IIOMetadata getImageMetadata(int imageIndex) + throws IOException + { + // FIXME: handle metadata + checkIndex(imageIndex); + return null; + } + + public Iterator getImageTypes(int imageIndex) + throws IOException + { + return null; + } + + public int getNumImages(boolean allowSearch) + throws IOException + { + return 1; + } + + public IIOMetadata getStreamMetadata() + throws IOException + { + // FIXME: handle metadata + return null; + } + + public int getWidth(int imageIndex) + throws IOException + { + checkIndex(imageIndex); + decodeStream(); + return decoder.getWidth(); + } + + public BufferedImage read(int imageIndex, ImageReadParam param) + throws IOException + { + checkIndex(imageIndex); + decodeStream(); + return decoder.getImage(); + } + + // private helper methods + private void checkIndex(int imageIndex) + throws IndexOutOfBoundsException + { + if (imageIndex != 0) + throw new IndexOutOfBoundsException(); + } + + private void checkStream() throws IOException + { + if (!(input instanceof ImageInputStream)) + throw new IllegalStateException("Input not an ImageInputStream."); + if(input == null) + throw new IllegalStateException("No input stream."); + } + + private void decodeStream() + throws IOException, IIOException + { + System.out.println("DECONDING 1"); + if (decoder != null) + return; + + System.out.println("DECONDING 2"); + checkStream(); + + System.out.println("DECONDING 3"); + decoder = new JPEGDecoder((ImageInputStream)input); + System.out.println("DECONDING 4"); + decoder.decode(); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageReaderSpi.java b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageReaderSpi.java new file mode 100644 index 000000000..c45b818c7 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageReaderSpi.java @@ -0,0 +1,137 @@ +/* JPEGImageReaderSpi.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +import java.io.IOException; +import java.util.Locale; +import javax.imageio.ImageReader; +import javax.imageio.spi.ImageReaderSpi; +import javax.imageio.spi.IIORegistry; +import javax.imageio.stream.ImageInputStream; + +public class JPEGImageReaderSpi extends ImageReaderSpi +{ + static final String vendorName = "GNU"; + static final String version = "0.1"; + static final String readerClassName = + "gnu.javax.imageio.jpeg.JPEGImageReader"; + static final String[] names = { "JPEG" }; + static final String[] suffixes = { ".jpeg", ".jpg", ".jpe" }; + static final String[] MIMETypes = { "image/jpeg" }; + static final String[] writerSpiNames = + { "gnu.javax.imageio.jpeg.JPEGImageWriterSpi" }; + + static final boolean supportsStandardStreamMetadataFormat = false; + static final String nativeStreamMetadataFormatName = null; + static final String nativeStreamMetadataFormatClassName = null; + static final String[] extraStreamMetadataFormatNames = null; + static final String[] extraStreamMetadataFormatClassNames = null; + static final boolean supportsStandardImageMetadataFormat = false; + static final String nativeImageMetadataFormatName = null; + static final String nativeImageMetadataFormatClassName = null; + static final String[] extraImageMetadataFormatNames = null; + static final String[] extraImageMetadataFormatClassNames = null; + + private static JPEGImageReaderSpi readerSpi; + + public JPEGImageReaderSpi() + { + super(vendorName, version, + names, suffixes, MIMETypes, + readerClassName, + STANDARD_INPUT_TYPE, // Accept ImageInputStreams + writerSpiNames, + supportsStandardStreamMetadataFormat, + nativeStreamMetadataFormatName, + nativeStreamMetadataFormatClassName, + extraStreamMetadataFormatNames, + extraStreamMetadataFormatClassNames, + supportsStandardImageMetadataFormat, + nativeImageMetadataFormatName, + nativeImageMetadataFormatClassName, + extraImageMetadataFormatNames, + extraImageMetadataFormatClassNames); + System.out.println ("JPEGImageReaderSPI!!!"); + } + + public String getDescription(Locale locale) + { + return "JPEG ISO 10918-1, JFIF V1.02"; + } + + public boolean canDecodeInput(Object input) + throws IOException + { + if (!(input instanceof ImageInputStream)) + return false; + + ImageInputStream in = (ImageInputStream) input; + boolean retval; + + in.mark(); + try + { + new JPEGDecoder(in); + retval = true; + } + catch(JPEGException e) + { + retval = false; + } + in.reset(); + + return retval; + } + + public ImageReader createReaderInstance(Object extension) + { + return new JPEGImageReader(this); + } + + public static void registerSpis(IIORegistry reg) + { + reg.registerServiceProvider(getReaderSpi(), ImageReaderSpi.class); + } + + public static synchronized JPEGImageReaderSpi getReaderSpi() + { + if (readerSpi == null) + readerSpi = new JPEGImageReaderSpi(); + return readerSpi; + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/JPEGMarker.java b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGMarker.java new file mode 100644 index 000000000..bc6350fbc --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGMarker.java @@ -0,0 +1,205 @@ +/* JPEGMarker.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +public class JPEGMarker +{ + /** + * JFIF identifiers. + */ + public final static byte JFIF_J = (byte) 0x4a; + public final static byte JFIF_F = (byte) 0x46; + public final static byte JFIF_I = (byte) 0x49; + public final static byte JFIF_X = (byte) 0x46; + + /** + * JFIF extension codes. + */ + public final static byte JFXX_JPEG = (byte) 0x10; + public final static byte JFXX_ONE_BPP = (byte) 0x11; + public final static byte JFXX_THREE_BPP = (byte) 0x13; + + /** + * Marker prefix byte. + */ + public final static byte XFF = (byte) 0xff; + + /** + * Marker byte that represents a literal 0xff. + */ + public final static byte X00 = (byte) 0x00; + + /** + * Application Reserved Keyword. + */ + public final static byte APP0 = (byte) 0xe0; + + public final static byte APP1 = (byte) 0xe1; + public final static byte APP2 = (byte) 0xe2; + public final static byte APP3 = (byte) 0xe3; + public final static byte APP4 = (byte) 0xe4; + public final static byte APP5 = (byte) 0xe5; + public final static byte APP6 = (byte) 0xe6; + public final static byte APP7 = (byte) 0xe7; + public final static byte APP8 = (byte) 0xe8; + public final static byte APP9 = (byte) 0xe9; + public final static byte APP10 = (byte) 0xea; + public final static byte APP11 = (byte) 0xeb; + public final static byte APP12 = (byte) 0xec; + public final static byte APP13 = (byte) 0xed; + public final static byte APP14 = (byte) 0xee; + public final static byte APP15 = (byte) 0xef; + + /** + * Modulo Restart Interval. + */ + public final static byte RST0 = (byte) 0xd0; + + public final static byte RST1 = (byte) 0xd1; + public final static byte RST2 = (byte) 0xd2; + public final static byte RST3 = (byte) 0xd3; + public final static byte RST4 = (byte) 0xd4; + public final static byte RST5 = (byte) 0xd5; + public final static byte RST6 = (byte) 0xd6; + public final static byte RST7 = (byte) 0xd7; + + /** + * Nondifferential Huffman-coding frame (baseline dct). + */ + public final static byte SOF0 = (byte) 0xc0; + + /** + * Nondifferential Huffman-coding frame (extended dct). + */ + public final static byte SOF1 = (byte) 0xc1; + + /** + * Nondifferential Huffman-coding frame (progressive dct). + */ + public final static byte SOF2 = (byte) 0xc2; + + /** + * Nondifferential Huffman-coding frame Lossless (Sequential). + */ + public final static byte SOF3 = (byte) 0xc3; + + /** + * Differential Huffman-coding frame Sequential DCT. + */ + public final static byte SOF5 = (byte) 0xc5; + + /** + * Differential Huffman-coding frame Progressive DCT. + */ + public final static byte SOF6 = (byte) 0xc6; + + /** + * Differential Huffman-coding frame lossless. + */ + public final static byte SOF7 = (byte) 0xc7; + + /** + * Nondifferential Arithmetic-coding frame (extended dct). + */ + public final static byte SOF9 = (byte) 0xc9; + + /** + * Nondifferential Arithmetic-coding frame (progressive dct). + */ + public final static byte SOF10 = (byte) 0xca; + + /** + * Nondifferential Arithmetic-coding frame (lossless). + */ + public final static byte SOF11 = (byte) 0xcb; + + /** + * Differential Arithmetic-coding frame (sequential dct). + */ + public final static byte SOF13 = (byte) 0xcd; + + /** + * Differential Arithmetic-coding frame (progressive dct). + */ + public final static byte SOF14 = (byte) 0xce; + + /** + * Differential Arithmetic-coding frame (lossless). + */ + public final static byte SOF15 = (byte) 0xcf; + + /** + * Huffman Table. + */ + public final static byte DHT = (byte) 0xc4; + + /** + * Quantization Table. + */ + public final static byte DQT = (byte) 0xdb; + + /** + * Start of Scan. + */ + public final static byte SOS = (byte) 0xda; + + /** + * Defined Restart Interval. + */ + public final static byte DRI = (byte) 0xdd; + + /** + * Comment in JPEG. + */ + public final static byte COM = (byte) 0xfe; + + /** + * Start of Image. + */ + public final static byte SOI = (byte) 0xd8; + + /** + * End of Image. + */ + public final static byte EOI = (byte) 0xd9; + + /** + * Define Number of Lines. + */ + public final static byte DNL = (byte) 0xdc; +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/JPEGMarkerFoundException.java b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGMarkerFoundException.java new file mode 100644 index 000000000..2e72d495b --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGMarkerFoundException.java @@ -0,0 +1,50 @@ +/* JPEGMarkerFoundException.java -- FIXME: briefly describe file purpose + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.imageio.jpeg; + +import java.io.IOException; + +public class JPEGMarkerFoundException + extends IOException +{ + public JPEGMarkerFoundException() + { + super(""); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/JPEGScan.java b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGScan.java new file mode 100644 index 000000000..e07251021 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGScan.java @@ -0,0 +1,151 @@ +/* JPEGScan.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +import java.util.ArrayList; + +public class JPEGScan +{ + private int maxHeight = 0, maxWidth = 0, maxV = 0, maxH = 0; + private int numOfComponents = 0, numOfComponentBlocks = 0; + private ArrayList components = new ArrayList(); + + public JPEGScan() + { + // Nothing to do here. + } + + public JPEGScan(int h, int w) + { + maxHeight=h; + maxWidth=w; + } + + private void recalculateDimensions() + { + JPEGComponent comp; + + // Compute the maximum H, maximum V factors defined in Annex A of the ISO + // DIS 10918-1. + for(int i=0; i < components.size() ; i++) + { + comp = (JPEGComponent)components.get(i); + if(comp.factorH > maxH) + maxH=comp.factorH; + if(comp.factorV > maxV) + maxV=comp.factorV; + } + + for(int i=0; i < components.size() ; i++) + { + comp = (JPEGComponent)components.get(i); + comp.maxH = maxH; + comp.maxV = maxV; + } + + } + + public void addComponent(byte id, byte factorHorizontal, byte factorVertical, + byte quantizationID) + { + JPEGComponent component = new JPEGComponent(id, factorHorizontal, factorVertical, quantizationID); + components.add((Object)component); + recalculateDimensions(); + numOfComponents++; + numOfComponentBlocks += factorHorizontal*factorVertical; + } + + public JPEGComponent getComponentByID(byte id) + { + JPEGComponent comp = (JPEGComponent)components.get(0); + for(int i=0; i < components.size() ; i++) + { + comp=(JPEGComponent)components.get(i); + if(comp.component_id==id) + break; + } + return(comp); + } + + public JPEGComponent get(int id) + { + return((JPEGComponent)components.get(id)); + } + + public int getX(byte id) + { + JPEGComponent comp = getComponentByID(id); + return(comp.width); + } + + public int getY(byte id) + { + JPEGComponent comp = getComponentByID(id); + return(comp.height); + } + + public int getMaxV() + { + return(maxV); + } + + public int getMaxH() + { + return(maxH); + } + + public void setWidth(int w) + { + maxWidth=w; + } + + public void setHeight(int h) + { + maxHeight=h; + } + + public int size() + { + return(numOfComponents); + } + + public int sizeComponentBlocks() + { + return(numOfComponentBlocks); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/YCbCr_ColorSpace.java b/libjava/classpath/gnu/javax/imageio/jpeg/YCbCr_ColorSpace.java new file mode 100644 index 000000000..a3970b7fa --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/YCbCr_ColorSpace.java @@ -0,0 +1,113 @@ +/* YCbCr_ColorSpace.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +import java.awt.color.ColorSpace; + +public class YCbCr_ColorSpace extends ColorSpace { + public YCbCr_ColorSpace() { + super(ColorSpace.TYPE_YCbCr, 3); + } + + public float[] fromCIEXYZ(float[] data) { + return(new float[data.length]); + } + + public float[] toCIEXYZ(float[] data) { + return(new float[data.length]); + } + + public float[] fromRGB(float[] data) { + return(new float[data.length]); + } + + /* YCbCr to RGB range 0 to 1 */ + public float[] toRGB(float[] data) { + float[] dest = new float[3]; + + data[0] *= 255; + data[1] *= 255; + data[2] *= 255; + + dest[0] = (float)data[0] + (float)1.402*((float)data[2]-(float)128); + dest[1] = (float)data[0] - (float)0.34414*((float)data[1]-(float)128) - (float)0.71414*((float)data[2]-(float)128); + dest[2] = (float)data[0] + (float)1.772*((float)data[1]-(float)128); + + dest[0] /= 255; + dest[1] /= 255; + dest[2] /= 255; + + //dest[0] = ((float)1.164*((float)data[0]*(float)255 - (float)16) + (float)1.596*((float)data[2]*(float)255 - (float)128))/(float)255; + //dest[1] = ((float)1.164*((float)data[0]*(float)255 - (float)16) - (float)0.813*((float)data[2]*(float)255 - (float)128) - (float)0.392*(data[1]*255 - 128))/(float)255; + //dest[2] = ((float)1.164*((float)data[0]*(float)255 - (float)16) + (float)2.017*((float)data[1]*(float)255 - (float)128))/(float)255; + + //System.err.println("toRGB values received: 0: "+data[0]+" 1: "+data[1]+" 2: "+data[2]+" sent: 0: "+dest[0]+" 1: "+dest[1]+" 2: "+dest[2]); + if(dest[0] < (float)0) + dest[0] = 0; + if(dest[1] < (float)0) + dest[1] = 0; + if(dest[2] < (float)0) + dest[2] = 0; + + if(dest[0] > (float)1) + dest[0] = 1; + if(dest[1] > (float)1) + dest[1] = 1; + if(dest[2] > (float)1) + dest[2] = 1; + + + return(dest); + } + + /* RGB to YCbCr range 0-255 */ + public static float[] toYCbCr(float[] data) { + float[] dest = new float[3]; + //dest[0] = (float)0.257*data[0] + (float)0.504*data[1] + (float)0.098*data[2] + 16; + //dest[1] = (float)-0.148*data[0] - (float)0.291*data[1] + (float)0.439*data[2] + 128; + //dest[2] = (float)0.439*data[0] - (float)0.368*data[1] - (float)0.071*data[2] + 128; + + dest[0] = (float)((0.299 * (float)data[0] + 0.587 * (float)data[1] + 0.114 * (float)data[2])); + dest[1] = 128 + (float)((-0.16874 * (float)data[0] - 0.33126 * (float)data[1] + 0.5 * (float)data[2])); + dest[2] = 128 + (float)((0.5 * (float)data[0] - 0.41869 * (float)data[1] - 0.08131 * (float)data[2])); + + + return(dest); + + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/ZigZag.java b/libjava/classpath/gnu/javax/imageio/jpeg/ZigZag.java new file mode 100644 index 000000000..9aac0df40 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/ZigZag.java @@ -0,0 +1,520 @@ +/* ZigZag.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.jpeg; + +/** + * This class implements the Zig Zag Algorithm on any array with + * the same amount of rows and columns. It takes a matrix and in turn builds an + * encoded byte array (or double array) from it. The adverse is also true, this + * will take a byte or double array and build a matrix based on the zig zag + * algorithm. + *

This is used exclusively in the JPEG DCT encoding.

+ */ +public class ZigZag +{ + public final static boolean ZIGZAG_FORWARD = true; + public final static boolean ZIGZAG_BACKWARD = false; + public final static int ZIGZAG_8X8_MAP[] = + { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 + }; + + /** + * Encodes a matrix of equal width and height to a byte array. + * + * @param matrix + * + * @return + */ + public static byte[] encode(byte[][] matrix) + { + byte[] buffer = new byte[matrix.length ^ 2]; + boolean direction = ZigZag.ZIGZAG_FORWARD; + int x = 0, y = 0, index = 0; + for (int zigIndex = 0; zigIndex < (matrix.length * 2 - 1); + zigIndex++, direction = !direction) + { + if (direction == ZigZag.ZIGZAG_FORWARD) + { + while (x >= 0 && y != matrix.length) + { + if (x == matrix.length) + { + x--; + y++; + } + buffer[index] = matrix[x][y]; + y++; + x--; + index++; + } + x++; + } + else + { + while (y >= 0 && x != matrix.length) + { + if (y == matrix.length) + { + y--; + x++; + } + buffer[index] = matrix[x][y]; + y--; + x++; + index++; + } + y++; + } + } + return (buffer); + } + + /** + * Encodes a matrix of equal width and height to a double array + * + * @param matrix + * + * @return + */ + public static double[] encode(double[][] matrix) + { + double[] buffer = new double[matrix.length * matrix.length]; + boolean direction = ZigZag.ZIGZAG_FORWARD; + int x = 0, y = 0, index = 0; + for (int zigIndex = 0; zigIndex < (matrix.length * 2 - 1); + zigIndex++, direction = !direction) + { + if (direction == ZigZag.ZIGZAG_FORWARD) + { + while (x >= 0 && y != matrix.length) + { + if (x == matrix.length) + { + x--; + y++; + } + buffer[index] = matrix[x][y]; + y++; + x--; + index++; + } + x++; + } + else + { + while (y >= 0 && x != matrix.length) + { + if (y == matrix.length) + { + y--; + x++; + } + buffer[index] = matrix[x][y]; + y--; + x++; + index++; + } + y++; + } + } + return (buffer); + } + + /** + * Encodes a matrix of equal width and height to a float array + * + * @param matrix + * + * @return + */ + public static float[] encode(float[][] matrix) + { + float[] buffer = new float[matrix.length * matrix.length]; + boolean direction = ZigZag.ZIGZAG_FORWARD; + int x = 0, y = 0, index = 0; + for (int zigIndex = 0; zigIndex < (matrix.length * 2 - 1); + zigIndex++, direction = !direction) + { + if (direction == ZigZag.ZIGZAG_FORWARD) + { + while (x >= 0 && y != matrix.length) + { + if (x == matrix.length) + { + x--; + y++; + } + buffer[index] = matrix[x][y]; + y++; + x--; + index++; + } + x++; + } + else + { + while (y >= 0 && x != matrix.length) + { + if (y == matrix.length) + { + y--; + x++; + } + buffer[index] = matrix[x][y]; + y--; + x++; + index++; + } + y++; + } + } + return (buffer); + } + + /** + * Encodes a matrix of equal width and height to a float array + * + * @param matrix + * + * @return + */ + public static short[] encode(short[][] matrix) + { + short[] buffer = new short[matrix.length * matrix.length]; + boolean direction = ZigZag.ZIGZAG_FORWARD; + int x = 0, y = 0, index = 0; + for (int zigIndex = 0; zigIndex < (matrix.length * 2 - 1); + zigIndex++, direction = !direction) + { + if (direction == ZigZag.ZIGZAG_FORWARD) + { + while (x >= 0 && y != matrix.length) + { + if (x == matrix.length) + { + x--; + y++; + } + buffer[index] = matrix[x][y]; + y++; + x--; + index++; + } + x++; + } + else + { + while (y >= 0 && x != matrix.length) + { + if (y == matrix.length) + { + y--; + x++; + } + buffer[index] = matrix[x][y]; + y--; + x++; + index++; + } + y++; + } + } + return (buffer); + } + + /** + * Convert a double array into a matrix with the same amount of columns and + * rows with length sqrt(double array length) + * + * @param data + * + * @return + */ + public static double[][] decode(double[] data) + { + return decode(data, (int) Math.sqrt(data.length), + (int) Math.sqrt(data.length)); + } + + /** + * Convert a byte array into a matrix with the same amount of columns and + * rows with length sqrt(double array length) + * + * @param data + * + * @return + */ + public static byte[][] decode(byte[] data) + { + return decode(data, (int) Math.sqrt(data.length), + (int) Math.sqrt(data.length)); + } + + public static int[][] decode(int[] data) + { + return decode(data, (int) Math.sqrt(data.length), + (int) Math.sqrt(data.length)); + } + + public static byte[][] decode(byte[] data, int width, int height) + { + byte[][] buffer = new byte[height][width]; + + for (int v = 0; v < height; v++) + for (int z = 0; z < width; z++) + buffer[v][z] = 11; + + boolean dir = ZigZag.ZIGZAG_FORWARD; + int xindex = 0, yindex = 0, dataindex = 0; + + while (xindex < width && yindex < height && dataindex < data.length) + { + buffer[yindex][xindex] = data[dataindex]; + dataindex++; + + if (dir == ZigZag.ZIGZAG_FORWARD) + { + if (yindex == 0 || xindex == (width - 1)) + { + dir = ZigZag.ZIGZAG_BACKWARD; + if (xindex == (width - 1)) + yindex++; + else + xindex++; + } + else + { + yindex--; + xindex++; + } + } + else + { /* Backwards */ + if (xindex == 0 || yindex == (height - 1)) + { + dir = ZigZag.ZIGZAG_FORWARD; + if (yindex == (height - 1)) + xindex++; + else + yindex++; + } + else + { + yindex++; + xindex--; + } + } + } + return (buffer); + } + + public static double[][] decode(double[] data, int width, int height) + { + double[][] buffer = new double[height][width]; + + for (int v = 0; v < height; v++) + for (int z = 0; z < width; z++) + buffer[v][z] = 11; + + boolean dir = ZigZag.ZIGZAG_FORWARD; + int xindex = 0, yindex = 0, dataindex = 0; + + while (xindex < width && yindex < height && dataindex < data.length) + { + buffer[yindex][xindex] = data[dataindex]; + dataindex++; + System.err.println("Setting " + dataindex + " to row: " + yindex + + " column: " + xindex + " yourval:" + + (yindex*8+xindex)); + if (dir == ZigZag.ZIGZAG_FORWARD) + { + if (yindex == 0 || xindex == (width - 1)) + { + dir = ZigZag.ZIGZAG_BACKWARD; + if (xindex == (width - 1)) + yindex++; + else + xindex++; + } + else + { + yindex--; + xindex++; + } + } + else + { /* Backwards */ + if (xindex == 0 || yindex == (height - 1)) + { + dir = ZigZag.ZIGZAG_FORWARD; + if (yindex == (height - 1)) + xindex++; + else + yindex++; + } + else + { + yindex++; + xindex--; + } + } + } + return (buffer); + } + + public static float[][] decode(float[] data, int width, int height) + { + float[][] buffer = new float[height][width]; + + for (int v = 0; v < height; v++) + for (int z = 0; z < width; z++) + buffer[v][z] = 11; + + boolean dir = ZigZag.ZIGZAG_FORWARD; + int xindex = 0, yindex = 0, dataindex = 0; + + while (xindex < width && yindex < height && dataindex < data.length) + { + buffer[yindex][xindex] = data[dataindex]; + dataindex++; + + if (dir == ZigZag.ZIGZAG_FORWARD) + { + if (yindex == 0 || xindex == (width - 1)) + { + dir = ZigZag.ZIGZAG_BACKWARD; + if (xindex == (width - 1)) + yindex++; + else + xindex++; + } + else + { + yindex--; + xindex++; + } + } + else + { /* Backwards */ + if (xindex == 0 || yindex == (height - 1)) + { + dir = ZigZag.ZIGZAG_FORWARD; + if (yindex == (height - 1)) + xindex++; + else + yindex++; + } + else + { + yindex++; + xindex--; + } + } + } + return (buffer); + } + + public static int[][] decode(int[] data, int width, int height) + { + int[][] buffer = new int[height][width]; + + for (int v = 0; v < height; v++) + for (int z = 0; z < width; z++) + buffer[v][z] = 11; + + boolean dir = ZigZag.ZIGZAG_FORWARD; + int xindex = 0, yindex = 0, dataindex = 0; + + while (xindex < width && yindex < height && dataindex < data.length) + { + buffer[yindex][xindex] = data[dataindex]; + dataindex++; + + if (dir == ZigZag.ZIGZAG_FORWARD) + { + if (yindex == 0 || xindex == (width - 1)) + { + dir = ZigZag.ZIGZAG_BACKWARD; + if (xindex == (width - 1)) + yindex++; + else + xindex++; + } + else + { + yindex--; + xindex++; + } + } + else + { /* Backwards */ + if (xindex == 0 || yindex == (height - 1)) + { + dir = ZigZag.ZIGZAG_FORWARD; + if (yindex == (height - 1)) + xindex++; + else + yindex++; + } + else + { + yindex++; + xindex--; + } + } + } + return (buffer); + } + + public static double[][] decode8x8_map(double input[]) + { + double[][] output = new double[8][8]; + for(int i=0; i < 64 ; i++) + output[ZIGZAG_8X8_MAP[i]/8][ZIGZAG_8X8_MAP[i]%8] = input[i]; + return (output); + } + +} diff --git a/libjava/classpath/gnu/javax/imageio/png/PNGChunk.java b/libjava/classpath/gnu/javax/imageio/png/PNGChunk.java new file mode 100644 index 000000000..ade0999fe --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/png/PNGChunk.java @@ -0,0 +1,283 @@ +/* PNGChunk.java -- Generic PNG chunk + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.png; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; + +/** + * Class to load and validate a generic PNG chunk. + */ +public class PNGChunk +{ + + /** + * CRC table and initialization code. + */ + private static long[] crcTable; + + static + { + long c; + crcTable = new long[256]; + + for(int i = 0; i < 256; i++) + { + c = i; + for(int j = 0; j < 8; j++) + if( (c & 1) == 1 ) + c = 0xEDB88320L ^ (c >> 1); + else + c = c >> 1; + crcTable[i] = c; + } + } + + /** + * (recognized) PNG chunk types. + */ + public static final int TYPE_HEADER = 0x49484452; // 'IHDR' + public static final int TYPE_PALETTE = 0x504c5445;// 'PLTE' + public static final int TYPE_DATA = 0x49444154; // 'IDAT' + public static final int TYPE_TIME = 0x74494d45; // 'tIME' + public static final int TYPE_END = 0x49454e44; // 'IEND' + public static final int TYPE_PHYS = 0x70485973; // 'pHYS' + public static final int TYPE_GAMMA = 0x67414d41; // 'gAMA' + public static final int TYPE_PROFILE = 0x69434350; // 'iCCP' + + /** + * The chunk type - Represented in the file as 4 ASCII bytes, + */ + private int type; + + /** + * The chunk data + */ + protected byte[] data; + + /** + * The chunk's crc + */ + private int crc; + + /** + * Constructor for reading a generic chunk. + */ + protected PNGChunk( int type, byte[] data, int crc ) + { + this.type = type; + this.data = data; + this.crc = crc; + } + + /** + * Constructor for creating new chunks. + * (only used by subclasses - creating a generic chunk is rather useless) + */ + protected PNGChunk( int type ) + { + this.type = type; + } + + /** + * Loads a chunk from an InputStream. Does not perform validation, + * but will throw an IOException if the read fails. + * @param in - th einputstream to read from + * @param strict - if true, a PNGException is thrown on all invalid chunks, + * if false, only critical chunks will throw PNGExceptions. + */ + public static PNGChunk readChunk(InputStream in, boolean strict) + throws IOException, PNGException + { + byte data[] = new byte[4]; + if( in.read( data ) != 4 ) + throw new IOException("Could not read chunk length."); + int length = ((data[0] & 0xFF) << 24) | ((data[1] & 0xFF) << 16 ) | + ((data[2] & 0xFF) << 8) | (data[3] & 0xFF); + + if( in.read( data ) != 4 ) + throw new IOException("Could not read chunk type."); + int type = ((data[0] & 0xFF) << 24) | ((data[1] & 0xFF) << 16 ) | + ((data[2] & 0xFF) << 8) | (data[3] & 0xFF); + + byte[] chkdata = new byte[ length ]; + if( in.read( chkdata ) != length ) + throw new IOException("Could not read chunk data."); + + if( in.read( data ) != 4 ) + throw new IOException("Could not read chunk CRC."); + + int crc = ((data[0] & 0xFF) << 24) | ( (data[1] & 0xFF) << 16 ) | + ((data[2] & 0xFF) << 8) | (data[3] & 0xFF); + + if( strict ) + return getChunk( type, chkdata, crc ); + else + { + try + { + return getChunk( type, chkdata, crc ); + } + catch(PNGException pnge) + { + if( isEssentialChunk( type ) ) + throw pnge; + return null; + } + } + } + + /** + * Returns a specialied object for a chunk, if we have one. + */ + private static PNGChunk getChunk( int type, byte[] data, int crc ) + throws PNGException + { + switch( type ) + { + case TYPE_HEADER: + return new PNGHeader( type, data, crc ); + case TYPE_DATA: + return new PNGData( type, data, crc ); + case TYPE_PALETTE: + return new PNGPalette( type, data, crc ); + case TYPE_TIME: + return new PNGTime( type, data, crc ); + case TYPE_PHYS: + return new PNGPhys( type, data, crc ); + case TYPE_GAMMA: + return new PNGGamma( type, data, crc ); + case TYPE_PROFILE: + return new PNGICCProfile( type, data, crc ); + default: + return new PNGChunk( type, data, crc ); + } + } + + /** + * Returns whether the chunk is essential or not + */ + private static boolean isEssentialChunk( int type ) + { + switch( type ) + { + case TYPE_HEADER: + case TYPE_DATA: + case TYPE_PALETTE: + case TYPE_END: + return true; + default: + return false; + } + } + + /** + * Validates the chunk + */ + public boolean isValidChunk() + { + return (crc == calcCRC()); + } + + /** + * Returns the chunk type. + */ + public int getType() + { + return type; + } + + /** + * Writes a PNG chunk to an output stream, + * performing the CRC calculation as well. + */ + public void writeChunk(OutputStream out) throws IOException + { + out.write( getInt(data.length) ); + out.write( getInt(type) ); + out.write( data ); + out.write( getInt(calcCRC()) ); + } + + /** + * Return whether the chunk contains any data. + */ + public boolean isEmpty() + { + return ( data.length == 0 ); + } + + /** + * Convenience method. Cast an int to four bytes (big endian). + * (Now why doesn't java have a simple way of doing this?) + */ + public static byte[] getInt(int intValue) + { + long i = (intValue & 0xFFFFFFFFL); + byte[] b = new byte[4]; + b[0] = (byte)((i & 0xFF000000L) >> 24); + b[1] = (byte)((i & 0x00FF0000L) >> 16); + b[2] = (byte)((i & 0x0000FF00L) >> 8); + b[3] = (byte)(i & 0x000000FFL); + return b; + } + + /** + * Calculates this chunk's CRC value. + */ + private int calcCRC() + { + long c = 0xFFFFFFFFL; + byte[] t = getInt( type ); + for(int i = 0; i < 4; i++) + c = crcTable[ (int)((c ^ t[i]) & 0xFF) ] ^ (c >> 8); + + for(int i = 0; i < data.length; i++) + c = crcTable[ (int)((c ^ data[i]) & 0xFF) ] ^ (c >> 8); + + return (int)(c ^ 0xFFFFFFFFL); + } + + public String toString() + { + return "PNG Chunk. Type: " + new String( getInt(type) ) + " , CRC: " + + crc + " , calculated CRC: "+calcCRC(); + } + +} diff --git a/libjava/classpath/gnu/javax/imageio/png/PNGData.java b/libjava/classpath/gnu/javax/imageio/png/PNGData.java new file mode 100644 index 000000000..08d765f66 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/png/PNGData.java @@ -0,0 +1,104 @@ +/* PNGData.java -- PNG IDAT chunk. + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.png; + +import java.util.zip.Inflater; +import java.util.zip.Deflater; + +/** + * A PNG IDAT (data) chunk. + */ +public class PNGData extends PNGChunk +{ + private int offset; + + protected PNGData( int type, byte[] data, int crc ) + { + super( type, data, crc ); + } + + protected PNGData( int chunkSize ) + { + super( PNGChunk.TYPE_DATA ); + data = new byte[ chunkSize ]; + offset = 0; + } + + /** + * Deflates the available data in def to the chunk. + * + * @return true if the chunk is filled and no more data can be written, + * false otherwise. + */ + public void deflateToChunk( Deflater def ) + { + offset += def.deflate( data, offset, data.length - offset ); + } + + /** + * Returns true if the chunk is filled. + */ + public boolean chunkFull() + { + return (offset >= data.length); + } + + /** + * Shrink the chunk to offset size, used for the last chunk in a stream + * (no trailing data!) + */ + public void shrink() + { + byte[] newData = new byte[ offset ]; + System.arraycopy( data, 0, newData, 0, offset ); + data = newData; + } + + /** + * Feeds the data in the chunk to a ZIP inflater object. + */ + public void feedToInflater( Inflater inf ) + { + inf.setInput( data ); + } + + public String toString() + { + return "PNG Data chunk. Length = "+data.length; + } +} diff --git a/libjava/classpath/gnu/javax/imageio/png/PNGDecoder.java b/libjava/classpath/gnu/javax/imageio/png/PNGDecoder.java new file mode 100644 index 000000000..4481107c4 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/png/PNGDecoder.java @@ -0,0 +1,331 @@ +/* PNGDecoder.java + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.png; + +import java.util.zip.Inflater; +import java.util.zip.DataFormatException; +import java.awt.image.ColorModel; +import java.awt.image.ComponentColorModel; +import java.awt.image.ComponentSampleModel; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.DataBufferUShort; +import java.awt.image.IndexColorModel; +import java.awt.image.MultiPixelPackedSampleModel; +import java.awt.image.Raster; +import java.awt.image.SampleModel; +import java.awt.image.SinglePixelPackedSampleModel; +import java.awt.image.WritableRaster; +import java.awt.color.ColorSpace; + +public class PNGDecoder +{ + private PNGHeader header; + private byte[] raster; + private byte[] scanline, lastScanline; + private byte[] filterType; + private int offset, length; + private int currentScanline; + private final int stride; + private Inflater inflater; + private boolean readFilter; + private int bpp; // bytes per pixel + + /** + * Constructs a filter object for + */ + public PNGDecoder(PNGHeader header) + { + this.header = header; + offset = 0; + inflater = new Inflater(); + stride = header.getScanlineStride(); + length = stride * header.getHeight(); + + // Allocate the output raster + raster = new byte[ length ]; + scanline = new byte[ stride ]; + lastScanline = new byte[ stride ]; + currentScanline = 0; + readFilter = true; + bpp = header.bytesPerPixel(); + filterType = new byte[1]; + inflater = new Inflater(); + } + + private int getBytes( byte[] buf, int offset ) throws PNGException + { + try + { + return inflater.inflate( buf, offset, buf.length - offset); + } + catch(DataFormatException dfe) + { + throw new PNGException("Error inflating data."); + } + } + + /** + * Decodes a data chunk. + */ + public void addData( PNGData chunk ) throws PNGException + { + int n = 0; + if( isFinished() ) + return; + chunk.feedToInflater( inflater ); + do + { + if( readFilter ) + if( getBytes( filterType, 0 ) < 1 ) + return; + + n = getBytes( scanline, offset ); + + if( offset + n < stride ) + { + offset += n; + readFilter = false; + } + else + { + scanline = PNGFilter.unFilterScanline( filterType[0], scanline, + lastScanline, bpp ); + System.arraycopy( scanline, 0, + raster, currentScanline * stride, stride ); + lastScanline = scanline; + scanline = new byte[scanline.length]; + currentScanline++; + readFilter = true; + offset = 0; + } + } + while( n > 0 && currentScanline < header.getHeight() ); + } + + /** + * Parse the appropriate color type and create an AWT raster for it. + * @param header - the file header. + */ + public WritableRaster getRaster( PNGHeader header ) + { + SampleModel sm = null; + DataBuffer db = null; + int t; + int width = header.getWidth(); + int height = header.getHeight(); + int depth = header.getDepth(); + + switch( header.getColorType() ) + { + case PNGHeader.GRAYSCALE_WITH_ALPHA: + if( depth == 8 ) + { + t = DataBuffer.TYPE_BYTE; + db = getByteBuffer(); + } + else + { + t = DataBuffer.TYPE_USHORT; + db = getShortBuffer(); + } + sm = new ComponentSampleModel(t, width, height, 2, width * 2, + new int[]{0, 1}); + break; + + case PNGHeader.GRAYSCALE: + switch( depth ) + { + case 16: + sm = new ComponentSampleModel(DataBuffer.TYPE_USHORT, + width, height, 1, width, + new int[]{ 0 }); + db = getShortBuffer(); + break; + + case 8: + sm = new ComponentSampleModel(DataBuffer.TYPE_BYTE, + width, height, 1, width, + new int[]{ 0 }); + db = getByteBuffer(); + break; + + default: + sm = new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, + width, height, depth); + db = getByteBuffer(); + break; + } + break; + + case PNGHeader.RGB: + if( depth == 8 ) + { + t = DataBuffer.TYPE_BYTE; + db = getByteBuffer(); + } + else + { + t = DataBuffer.TYPE_USHORT; + db = getShortBuffer(); + } + sm = new ComponentSampleModel(t, width, height, 3, 3 * width, + new int[]{0, 1, 2}); + break; + + case PNGHeader.RGB_WITH_ALPHA: + if( depth == 8 ) + { + t = DataBuffer.TYPE_BYTE; + db = getByteBuffer(); + } + else + { + t = DataBuffer.TYPE_USHORT; + db = getShortBuffer(); + } + + sm = new ComponentSampleModel(t, width, height, 4, width * 4, + new int[]{0, 1, 2, 3}); + break; + + case PNGHeader.INDEXED: + if( depth == 8 ) + sm = new SinglePixelPackedSampleModel(DataBuffer.TYPE_BYTE, + width, height, + new int[] {0xFF}); + else + sm = new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, + width, height, depth); + db = getByteBuffer(); + break; + } + + return Raster.createWritableRaster(sm, db, null); + } + + /** + * Wrap the raster with a DataBufferUShort, + * conversion is big-endian (PNG native). + */ + private DataBuffer getShortBuffer() + { + short[] data = new short[(raster.length >> 1)]; + for( int i = 0; i < data.length; i++ ) + data[i] = (short)(((raster[i * 2] & 0xFF) << 8) | + (raster[i * 2 + 1] & 0xFF)); + return new DataBufferUShort( data, data.length ); + } + + /** + * Wrap the raster with a DataBufferByte + */ + private DataBuffer getByteBuffer() + { + return new DataBufferByte( raster, raster.length ); + } + + public ColorModel getColorModel( ColorSpace cs, + int colorType, int depth ) + { + int[] bits; + boolean hasAlpha = false; + int transferType; + + switch( colorType ) + { + case PNGHeader.GRAYSCALE_WITH_ALPHA: + if( cs == null ) + cs = ColorSpace.getInstance( ColorSpace.CS_GRAY ); + hasAlpha = true; + bits = new int[]{ depth, depth }; + break; + + case PNGHeader.RGB: + bits = new int[]{ depth, depth, depth }; + break; + + case PNGHeader.RGB_WITH_ALPHA: + hasAlpha = true; + bits = new int[]{ depth, depth, depth, depth }; + break; + + case PNGHeader.GRAYSCALE: + if( depth < 8 ) + return grayPalette( depth ); + + if( cs == null ) + cs = ColorSpace.getInstance( ColorSpace.CS_GRAY ); + bits = new int[]{ depth }; + break; + + default: + case PNGHeader.INDEXED: + return null; // Handled by the palette chunk. + } + + if( cs == null ) + cs = ColorSpace.getInstance( ColorSpace.CS_sRGB ); + + + return new ComponentColorModel(cs, bits, hasAlpha, false, + (hasAlpha ? + ComponentColorModel.TRANSLUCENT : + ComponentColorModel.OPAQUE), + ((depth == 16) ? DataBuffer.TYPE_USHORT : + DataBuffer.TYPE_BYTE)); + } + + private IndexColorModel grayPalette(int depth) + { + byte[] c = new byte[ (1 << depth) ]; + for(int i = 0; i < c.length; i++) + c[i] = (byte)(255.0 * (((double)i) / ((double)c.length - 1.0))); + return new IndexColorModel(8, c.length, c, c, c); + } + + public byte[] getRaster() + { + return raster; + } + + public boolean isFinished() + { + return currentScanline >= header.getHeight(); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/png/PNGEncoder.java b/libjava/classpath/gnu/javax/imageio/png/PNGEncoder.java new file mode 100644 index 000000000..b31787635 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/png/PNGEncoder.java @@ -0,0 +1,233 @@ +/* PNGEncoder.java -- + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.png; + +import java.util.Vector; +import java.util.zip.Deflater; +import java.awt.color.ColorSpace; +import java.awt.color.ICC_ColorSpace; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.DataBufferUShort; +import java.awt.image.IndexColorModel; +import java.awt.image.WritableRaster; + +public class PNGEncoder +{ + /** + * The default data chunk size. 8 kb. + */ + private static final int defaultChunkSize = 8192; + + private PNGHeader header; + private PNGPalette palette; + private int stride, bpp; + private byte[] rawData; + private PNGICCProfile profile; + + public PNGEncoder( BufferedImage bi ) throws PNGException + { + ColorModel c = bi.getColorModel(); + int width = bi.getWidth(); + int height = bi.getHeight(); + int depth = 0; + int colorType; + boolean interlace = false; + + if( c instanceof IndexColorModel ) + { + colorType = PNGHeader.INDEXED; + int n = ((IndexColorModel)c).getMapSize(); + if( n <= 2 ) + depth = 1; + else if( n <= 4 ) + depth = 2; + else if( n <= 16 ) + depth = 4; + else if( n <= 256 ) + depth = 8; + else + throw new PNGException("Depth must be <= 8 bits for indexed color."); + palette = new PNGPalette( ((IndexColorModel)c) ); + } + else + { + ColorSpace cs = c.getColorSpace(); + ColorSpace grayCS = ColorSpace.getInstance( ColorSpace.CS_GRAY ); + if( cs == grayCS || bi.getType() == BufferedImage.TYPE_BYTE_GRAY + || bi.getType() == BufferedImage.TYPE_USHORT_GRAY ) + colorType = c.hasAlpha() ? PNGHeader.GRAYSCALE_WITH_ALPHA : + PNGHeader.GRAYSCALE; + else + colorType = c.hasAlpha() ? PNGHeader.RGB_WITH_ALPHA : PNGHeader.RGB; + // Figure out the depth + int[] bits = c.getComponentSize(); + depth = bits[0]; + for(int i = 1; i < bits.length; i++ ) + if( bits[i] > depth ) depth = bits[i]; + if( (cs != grayCS && !cs.isCS_sRGB()) && cs instanceof ICC_ColorSpace ) + profile = new PNGICCProfile( ((ICC_ColorSpace)cs).getProfile() ); + } + + header = new PNGHeader(width, height, depth, colorType, interlace); + + stride = header.getScanlineStride(); // scanline stride + bpp = header.bytesPerPixel(); // bytes per pixel + getRawData( bi ); + } + + /** + * Returns the generated header. + */ + public PNGHeader getHeader() + { + return header; + } + + /** + * Returns the generated palette. + */ + public PNGPalette getPalette() + { + return palette; + } + + /** + * Returns the associated ICC profile, if any. + */ + public PNGICCProfile getProfile() + { + return profile; + } + + /** + * Encodes the raster and returns a Vector of PNGData chunks. + */ + public Vector encodeImage() + { + Deflater deflater = new Deflater(); // The deflater + boolean useFilter = PNGFilter.useFilter( header ); + byte[] lastScanline = new byte[ stride ]; + + byte[] data = new byte[ rawData.length + header.getHeight() ]; + + byte filterByte = PNGFilter.FILTER_NONE; + for( int i = 0; i < header.getHeight(); i++) + { + byte[] scanline = new byte[ stride ]; + System.arraycopy(rawData, (i * stride), scanline, 0, stride); + if( useFilter && i > 0) + filterByte = PNGFilter.chooseFilter( scanline, lastScanline, bpp); + + byte[] filtered = PNGFilter.filterScanline( filterByte, scanline, + lastScanline, bpp ); + data[i * (stride + 1)] = filterByte; + System.arraycopy(filtered, 0, data, 1 + (i * (stride + 1)), stride); + + lastScanline = scanline; + } + + deflater.setInput( data ); + deflater.finish(); + + PNGData chunk; + Vector chunks = new Vector(); + do + { + chunk = new PNGData( defaultChunkSize ); + chunk.deflateToChunk( deflater ); + chunks.add( chunk ); + } + while( chunk.chunkFull() ); + chunk.shrink(); // Shrink the last chunk. + return chunks; + } + + /** + * Get the image's raw data. + * FIXME: This may need improving on. + */ + private void getRawData( BufferedImage bi ) throws PNGException + { + WritableRaster raster = bi.getRaster(); + rawData = new byte[ stride * header.getHeight() ]; + if( header.isIndexed() ) + { + DataBuffer db = raster.getDataBuffer(); + if( !( db instanceof DataBufferByte ) ) + throw new PNGException("Unexpected DataBuffer for an IndexColorModel."); + byte[] data = ((DataBufferByte)db).getData(); + for(int i = 0; i < header.getHeight(); i++ ) + System.arraycopy( data, i * stride, rawData, i * stride, stride ); + return; + } + + if( header.getDepth() == 16 ) + { + DataBuffer db = raster.getDataBuffer(); + if( !( db instanceof DataBufferUShort ) ) + throw new PNGException("Unexpected DataBuffer for 16-bit."); + short[] data = ((DataBufferUShort)db).getData(); + for(int i = 0; i < header.getHeight(); i++ ) + for(int j = 0; j < ( stride >> 1); j++) + { + rawData[ j * 2 + i * stride ] = (byte)((data[j + i * (stride >> 1 )] & 0xFF00) >> 8); + rawData[ j * 2 + i * stride + 1 ] = (byte)(data[j + i * (stride >> 1 )] & 0xFF); + } + return; + } + + int size = ( header.getColorType() == PNGHeader.RGB_WITH_ALPHA ) ? 4 : 3; + int width = header.getWidth(); + int height = header.getHeight(); + int[] pixels = bi.getRGB( 0, 0, width, height, null, 0, width ); + + for( int i = 0; i < width * height; i++ ) + { + rawData[ i * size ] = (byte)((pixels[i] & 0xFF0000) >> 16); + rawData[ i * size + 1 ] = (byte)((pixels[i] & 0xFF00) >> 8); + rawData[ i * size + 2 ] = (byte)(pixels[i] & 0xFF); + } + + if( size == 4 ) + for( int i = 0; i < width * height; i++ ) + rawData[ i * size + 3 ] = (byte)((pixels[i] & 0xFF000000) >> 24); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/png/PNGException.java b/libjava/classpath/gnu/javax/imageio/png/PNGException.java new file mode 100644 index 000000000..ef5342cf8 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/png/PNGException.java @@ -0,0 +1,48 @@ +/* PNGException.java -- + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.png; + +import java.io.IOException; + +public class PNGException extends IOException +{ + public PNGException(String msg) + { + super( msg ); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/png/PNGFile.java b/libjava/classpath/gnu/javax/imageio/png/PNGFile.java new file mode 100644 index 000000000..76154cc66 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/png/PNGFile.java @@ -0,0 +1,257 @@ +/* PNGFile.java -- High-level representation of a PNG file. + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.png; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; +import java.util.Vector; +import java.awt.image.BufferedImage; +import java.awt.image.WritableRaster; +import java.awt.image.ColorModel; +import java.awt.color.ColorSpace; + +public class PNGFile +{ + /** + * The PNG file signature. + */ + private static final byte[] signature = new byte[] + { (byte)137, 80, 78, 71, 13, 10, 26, 10 }; + + /** + * The end chunk in raw form, no need for anything fancy here, it's just + * 0 bytes of length, the "IEND" tag and its CRC. + */ + private static final byte[] endChunk = new byte[] + { 0, 0, 0, 0, (byte)0x49, (byte)0x45, (byte)0x4E, (byte)0x44, + (byte)0xAE, (byte)0x42, (byte)0x60, (byte)0x82 }; + + /** + * The loaded data. + */ + private Vector chunks; + + /** + * The Header chunk + */ + private PNGHeader header; + + /** + * Whether this file has a palette chunk or not. + */ + private boolean hasPalette; + + /** + * Image width and height. + */ + private int width, height; + + /** + * The decoder, if any. + */ + private PNGDecoder decoder; + + /** + * The encoder, if any. (Either this or the above must exist). + */ + private PNGEncoder encoder; + + /** + * The source of this PNG (if encoding) + */ + private BufferedImage sourceImage; + + /** + * Creates a PNGFile object from an InputStream. + */ + public PNGFile(InputStream in) throws IOException, PNGException + { + PNGChunk chunk; + byte[] fileHdr = new byte[8]; + chunks = new Vector(); + hasPalette = false; + + if( in.read( fileHdr ) != 8 ) + throw new IOException("Could not read file header."); + if( !validateHeader( fileHdr ) ) + throw new PNGException("Invalid file header. Not a PNG file."); + + chunk = PNGChunk.readChunk( in, false ); + if( !(chunk instanceof PNGHeader) ) + throw new PNGException("First chunk not a header chunk."); + header = (PNGHeader)chunk; + if( !header.isValidChunk() ) + throw new PNGException("First chunk not a valid header."); + System.out.println(header); + + decoder = new PNGDecoder( header ); + // Read chunks. + do + { + chunk = PNGChunk.readChunk( in, false ); + /* + * We could exit here or output some kind of warning. + * But in the meantime, we'll just silently drop invalid chunks. + */ + if( chunk.isValidChunk() ) + { + if( chunk instanceof PNGData ) + decoder.addData( (PNGData)chunk ); + else // Silently ignore multiple headers, and use only the first. + if( chunk.getType() != PNGChunk.TYPE_END ) + { + chunks.add( chunk ); + hasPalette |= ( chunk instanceof PNGPalette ); + } + } + else + System.out.println("WARNING: Invalid chunk!"); + } + while( chunk.getType() != PNGChunk.TYPE_END ); + + if( header.isIndexed() && !hasPalette ) + throw new PNGException("File is indexed color and has no palette."); + + width = header.getWidth(); + height = header.getHeight(); + } + + /** + * Creates a PNG file from an existing BufferedImage. + */ + public PNGFile(BufferedImage bi) throws PNGException + { + sourceImage = bi; + width = bi.getWidth(); + height = bi.getHeight(); + chunks = new Vector(); + encoder = new PNGEncoder( bi ); + header = encoder.getHeader(); + if( header.isIndexed() ) + chunks.add( encoder.getPalette() ); + + // Do the compression and put the data chunks in the list. + chunks.addAll( encoder.encodeImage() ); + } + + /** + * Writes a PNG file to an OutputStream + */ + public void writePNG(OutputStream out) throws IOException + { + out.write( signature ); // write the signature. + header.writeChunk( out ); + for( int i = 0; i < chunks.size(); i++ ) + { + PNGChunk chunk = ((PNGChunk)chunks.elementAt(i)); + chunk.writeChunk( out ); + } + out.write( endChunk ); + } + + /** + * Check 8 bytes to see if it's a valid PNG header. + */ + private boolean validateHeader( byte[] hdr ) + { + if( hdr.length != 8 ) + return false; + for( int i = 0; i < 8; i++ ) + if( signature[i] != hdr[i] ) + return false; + return true; + } + + /** + * Return a loaded image as a bufferedimage. + */ + public BufferedImage getBufferedImage() + { + if( decoder == null ) + return sourceImage; + + WritableRaster r = decoder.getRaster( header ); + ColorModel cm; + if( header.isIndexed() ) + { + PNGPalette pngp = getPalette(); + cm = pngp.getPalette( getColorSpace() ); + } + else + cm = decoder.getColorModel( getColorSpace(), + header.getColorType(), + header.getDepth() ); + + return new BufferedImage(cm, r, false, null); + } + + /** + * Find the palette chunk and return it + */ + private PNGPalette getPalette() + { + for(int i = 0; i < chunks.size(); i++ ) + if( chunks.elementAt(i) instanceof PNGPalette ) + return ((PNGPalette)chunks.elementAt(i)); + return null; + } + + /** + * Return the Color space to use, first preference is ICC profile, then + * a gamma chunk, or returns null for the default sRGB. + */ + private ColorSpace getColorSpace() + { + PNGICCProfile icc = null; + PNGGamma gamma = null; + for(int i = 0; i < chunks.size(); i++ ) + { + if( chunks.elementAt(i) instanceof PNGICCProfile ) + icc = ((PNGICCProfile)chunks.elementAt(i)); + else if(chunks.elementAt(i) instanceof PNGGamma ) + gamma = ((PNGGamma)chunks.elementAt(i)); + } + + if( icc != null ) + return icc.getColorSpace(); +// if( gamma != null && !header.isGrayscale()) +// return gamma.getColorSpace( header.isGrayscale() ); + return null; + } +} diff --git a/libjava/classpath/gnu/javax/imageio/png/PNGFilter.java b/libjava/classpath/gnu/javax/imageio/png/PNGFilter.java new file mode 100644 index 000000000..9be7b9127 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/png/PNGFilter.java @@ -0,0 +1,237 @@ +/* PNGFilter.java -- PNG image filters. + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.png; + +/** + * A utility class of static methods implementing the PNG filtering algorithms. + */ +public class PNGFilter +{ + + public static final byte FILTER_NONE = 0; + public static final byte FILTER_SUB = 1; + public static final byte FILTER_UP = 2; + public static final byte FILTER_AVERAGE = 3; + public static final byte FILTER_PAETH = 4; + + /** + * Return whether a filter should be used or FILTER_NONE, + * following the recommendations in the PNG spec. + */ + public static boolean useFilter( PNGHeader header ) + { + switch( header.getColorType() ) + { + case PNGHeader.INDEXED: + return false; + + case PNGHeader.GRAYSCALE: + case PNGHeader.RGB: + if( header.bytesPerPixel() <= 1 ) + return false; + case PNGHeader.GRAYSCALE_WITH_ALPHA: + case PNGHeader.RGB_WITH_ALPHA: + default: + return true; + } + } + + /** + * Heuristic for adaptively choosing a filter, following the scheme + * suggested in the PNG spec. + * @return a fiter type. + */ + public static byte chooseFilter( byte[] scanline, byte[] lastScanline, + int bpp) + + { + long[] values = new long[5]; + int idx = 0; + for( int i = 0; i < 5; i++ ) + { + byte[] filtered = filterScanline((byte)i, scanline, lastScanline, bpp); + values[i] = 0; + for(int j = 0; j < filtered.length; j++ ) + values[i] += (int)(filtered[j] & 0xFF); + if( values[ idx ] > values[i] ) + idx = i; + } + return (byte)idx; + } + + /** + * Filter a scanline. + */ + public static byte[] filterScanline( byte filtertype, byte[] scanline, + byte[] lastScanline, int bpp) + { + int stride = scanline.length; + byte[] out = new byte[ stride ]; + switch( filtertype ) + { + case FILTER_SUB: + for( int i = 0; i < bpp; i++) + out[ i ] = scanline[ i ]; + + for( int i = bpp; i < stride; i++ ) + out[i] = (byte)(scanline[ i ] - + scanline[ i - bpp ]); + break; + + case FILTER_UP: + for( int i = 0; i < stride; i++ ) + out[ i ] = (byte)(scanline[ i ] - lastScanline[ i ]); + break; + + case FILTER_AVERAGE: + for( int i = 0; i < bpp; i++) + out[ i ] = (byte)((scanline[ i ] & 0xFF) - ((lastScanline[ i ] & 0xFF) >> 1)); + for( int i = bpp; i < stride; i++ ) + out[ i ] = (byte)((scanline[ i ] & 0xFF) - + (((scanline[ i - bpp ] & 0xFF) + + (lastScanline[ i ] & 0xFF)) >> 1)); + break; + + case FILTER_PAETH: + for( int i = 0; i < stride; i++ ) + { + int x; + { + int a, b, c; + if( i >= bpp ) + { + a = (scanline[ i - bpp ] & 0xFF); // left + c = (lastScanline[ i - bpp ] & 0xFF); // upper-left + } + else + a = c = 0; + b = (lastScanline[ i ] & 0xFF); // up + + int p = (a + b - c); // initial estimate + // distances to a, b, c + int pa = (p > a) ? p - a : a - p; + int pb = (p > b) ? p - b : b - p; + int pc = (p > c) ? p - c : c - p; + // return nearest of a,b,c, + // breaking ties in order a,b,c. + if( pa <= pb && pa <= pc ) x = a; + else { if( pb <= pc ) x = b; + else x = c; + } + } + out[ i ] = (byte)(scanline[ i ] - x); + } + break; + default: + case FILTER_NONE: + return scanline; + } + return out; + } + + /** + * Unfilter a scanline. + */ + public static byte[] unFilterScanline( int filtertype, byte[] scanline, + byte[] lastScanline, int bpp) + { + int stride = scanline.length; + byte[] out = new byte[ stride ]; + switch( filtertype ) + { + + case FILTER_NONE: + System.arraycopy( scanline, 0, out, 0, stride ); + break; + + case FILTER_SUB: + for( int i = 0; i < bpp; i++) + out[ i ] = scanline[ i ]; + + for( int i = bpp; i < stride; i++ ) + out[ i ] = (byte)(scanline[ i ] + + out[ i - bpp ]); + break; + + case FILTER_UP: + for( int i = 0; i < stride; i++ ) + out[ i ] = (byte)(scanline[ i ] + lastScanline[ i ]); + break; + + case FILTER_AVERAGE: + for( int i = 0; i < bpp; i++) + out[ i ] = (byte)((scanline[ i ] & 0xFF) + ((lastScanline[ i ] & 0xFF) >> 1)); + for( int i = bpp; i < stride; i++ ) + out[ i ] = (byte)((scanline[ i ] & 0xFF) + + (((out[ i - bpp ] & 0xFF) + (lastScanline[ i ] & 0xFF)) >> 1)); + break; + + case FILTER_PAETH: + for( int i = 0; i < stride; i++ ) + { + int x; + { + int a, b, c; + if( i >= bpp ) + { + a = (out[ i - bpp ] & 0xFF); // left + c = (lastScanline[ i - bpp ] & 0xFF); // upper-left + } + else + a = c = 0; + b = (lastScanline[ i ] & 0xFF); // up + + int p = (a + b - c); // initial estimate + // distances to a, b, c + int pa = (p > a) ? p - a : a - p; + int pb = (p > b) ? p - b : b - p; + int pc = (p > c) ? p - c : c - p; + // return nearest of a,b,c, + // breaking ties in order a,b,c. + if( pa <= pb && pa <= pc ) x = a; + else { if( pb <= pc ) x = b; + else x = c; + } + } + out[ i ] = (byte)(scanline[ i ] + x); + } + break; + } + return out; + } +} diff --git a/libjava/classpath/gnu/javax/imageio/png/PNGGamma.java b/libjava/classpath/gnu/javax/imageio/png/PNGGamma.java new file mode 100644 index 000000000..b9c3f21c3 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/png/PNGGamma.java @@ -0,0 +1,85 @@ +/* PNGGamma.java -- GAMA chunk. + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.png; + +import java.awt.color.ColorSpace; + +/** + * A PNG gAMA (gamma) chunk. + */ +public class PNGGamma extends PNGChunk +{ + private double gamma; + + protected PNGGamma( int type, byte[] data, int crc ) throws PNGException + { + super( type, data, crc ); + if( data.length < 4 ) + throw new PNGException("Unexpectedly short time chunk. ("+data.length+" bytes)"); + long g = ((data[0] & 0xFF) << 24) | ( (data[1] & 0xFF) << 16 ) | + ((data[2] & 0xFF) << 8) | (data[3] & 0xFF); + gamma = (double)g; + gamma = 100000.0/gamma; + } + + public PNGGamma( double g ) + { + super( TYPE_GAMMA ); + data = new byte[ 4 ]; + gamma = g; + long tmp = (long)(100000.0/gamma); + data[0] = (byte)((tmp & 0xFF000000) >> 24); + data[1] = (byte)((tmp & 0xFF0000) >> 16); + data[2] = (byte)((tmp & 0xFF00) >> 8); + data[3] = (byte)(tmp & 0xFF); + } + + /** + * Returns a ColorSpace object corresponding to this gamma value. + */ + public ColorSpace getColorSpace(boolean grayscale) + { + // FIXME. + return null; + } + + public String toString() + { + return "PNG Gamma chunk, value: "+gamma; + } +} diff --git a/libjava/classpath/gnu/javax/imageio/png/PNGHeader.java b/libjava/classpath/gnu/javax/imageio/png/PNGHeader.java new file mode 100644 index 000000000..115e50311 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/png/PNGHeader.java @@ -0,0 +1,257 @@ +/* PNGHeader.java -- PNG Header + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.png; + +/** + * A PNG Header chunk. + */ +public class PNGHeader extends PNGChunk +{ + private int width, height, depth; + private int colorType, compression, filter, interlace; + + /** + * The valid interlace types. + */ + public static final int INTERLACE_NONE = 0; + public static final int INTERLACE_ADAM7 = 1; + + /** + * The valid color types. + */ + public static final int GRAYSCALE = 0; + public static final int RGB = 2; + public static final int INDEXED = 3; + public static final int GRAYSCALE_WITH_ALPHA = 4; + public static final int RGB_WITH_ALPHA = 6; + + /** + * Parses a PNG Header chunk. + */ + protected PNGHeader( int type, byte[] data, int crc ) throws PNGException + { + super( type, data, crc ); + if( data.length < 13 ) + throw new PNGException("Unexpectedly short header chunk. (" + data.length + + " bytes)"); + + width = ((data[0] & 0xFF) << 24) | ( (data[1] & 0xFF) << 16 ) | + ((data[2] & 0xFF) << 8) | (data[3] & 0xFF); + height = ((data[4] & 0xFF) << 24) | ( (data[5] & 0xFF) << 16 ) | + ((data[6] & 0xFF) << 8) | (data[7] & 0xFF); + depth = (data[8] & 0xFF); + colorType = (data[9] & 0xFF); + compression = (data[10] & 0xFF); + filter = (data[11] & 0xFF); + interlace = (data[12] & 0xFF); + } + + /** + * Create a PNG header chunk. + * Warning: This trusts that the parameters are valid. + */ + public PNGHeader(int width, int height, int depth, + int colorType, boolean interlace) + { + super( TYPE_HEADER ); + data = new byte[ 13 ]; + + this.width = width; + this.height = height; + this.depth = depth; + compression = filter = 0; + this.colorType = colorType; + this.interlace = interlace ? 1 : 0; + + // Build the data chunk. + byte[] a = getInt( width ); + byte[] b = getInt( height ); + data[0] = a[0]; data[1] = a[1]; data[2] = a[2]; data[3] = a[3]; + data[4] = b[0]; data[5] = b[1]; data[6] = b[2]; data[7] = b[3]; + data[8] = (byte)depth; + data[9] = (byte)colorType; + data[10] = (byte)compression; + data[11] = (byte)filter; + data[12] = (byte)this.interlace; + } + + /** + * Validates the header fields + */ + public boolean isValidChunk() + { + if( !super.isValidChunk() ) + return false; + + // width and height must be nonzero + if( width == 0 || height == 0 ) + return false; + // colorType can be 0,2,3,4,6 + if( (colorType & 0xFFFFFFF8) != 0 || colorType == 5 || colorType == 1) + return false; + // Possible valid depths are 1,2,4,8,16 + if( !((depth == 1) || (depth == 2) || (depth == 4) || + (depth == 8) || (depth == 16)) ) + return false; + if( colorType == INDEXED && depth == 16 ) + return false; + if( ( colorType == RGB || colorType == GRAYSCALE_WITH_ALPHA || + colorType == RGB_WITH_ALPHA ) && + depth < 8 ) + return false; + // Only compression and filter methods zero are defined + if( compression != 0 || filter != 0 ) + return false; + // Interlace methods, 0 and 1 are valid values. + if( (interlace & 0xFFFFFFFE) != 0 ) + return false; + + return true; + } + + /** + * Returns true if this PNG is indexed-color + */ + public boolean isIndexed() + { + return (colorType == INDEXED); + } + + /** + * Returns true if this PNG is grayscale + */ + public boolean isGrayscale() + { + return ((colorType == GRAYSCALE) || (colorType == GRAYSCALE_WITH_ALPHA)); + } + + /** + * Returns the color type of the image. + */ + public int getColorType() + { + return colorType; + } + + /** + * Returns whether the image is interlaced or not. + */ + public boolean isInterlaced() + { + return (interlace != 0); + } + + /** + * Returns the number of bytes per pixel. + */ + public int bytesPerPixel() + { + switch( colorType ) + { + case GRAYSCALE_WITH_ALPHA: + return ((depth * 2) >> 3); + case RGB: + return ((depth * 3) >> 3); + case RGB_WITH_ALPHA: + return ((depth * 4) >> 3); + + default: + case GRAYSCALE: + case INDEXED: + int i = (depth >> 3); + if( i > 0 ) return i; + return 1; // if bytes per pixel < 1, return 1 anyway. + } + } + + /** + * Returns the stride of one scanline, in bytes. + */ + public int getScanlineStride() + { + long nBits = 0; // bits per scanline - scanlines are on byte offsets. + switch( colorType ) + { + case GRAYSCALE: + nBits = width * depth; + break; + case RGB: + nBits = width * depth * 3; + break; + case INDEXED: + nBits = depth * width; + break; + case GRAYSCALE_WITH_ALPHA: + nBits = depth * width * 2; + break; + case RGB_WITH_ALPHA: + nBits = depth * width * 4; + break; + } + // Round up number of bits to the nearest byte + if( (nBits & 0x07) != 0 ) + nBits += (8 - (nBits & 0x07)); + + return (int)(nBits >> 3); // return # of bytes. + } + + public int getWidth() + { + return width; + } + + public int getHeight() + { + return height; + } + + public int getDepth() + { + return depth; + } + + /** + * Debugging string. + */ + public String toString() + { + return "Header Chunk. Image width:"+width+" height:"+height+ + " depth:"+depth+" color type:"+colorType+" compression type:"+ + compression+" filter type:"+ filter+" interlace:"+interlace; + } +} diff --git a/libjava/classpath/gnu/javax/imageio/png/PNGICCProfile.java b/libjava/classpath/gnu/javax/imageio/png/PNGICCProfile.java new file mode 100644 index 000000000..9ecea7166 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/png/PNGICCProfile.java @@ -0,0 +1,116 @@ +/* PNGICCProfile.java -- + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.png; + +import java.awt.color.ICC_Profile; +import java.awt.color.ICC_ColorSpace; +import java.awt.color.ColorSpace; +import java.io.UnsupportedEncodingException; +import java.io.IOException; +import java.io.ByteArrayInputStream; +import java.util.zip.InflaterInputStream; +import java.util.zip.Deflater; + +/** + * A PNG iCCP (ICC Profile) chunk. + */ +public class PNGICCProfile extends PNGChunk +{ + private String name; + private ICC_Profile profile; + // A generic profile name to use "ICC Profile" + private static final byte[] genericName = new byte[] + { 0x49, 0x43, 0x43, 0x20, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65 }; + + protected PNGICCProfile( int type, byte[] data, int crc ) throws PNGException + { + super( type, data, crc ); + int i = 0; + while( data[i++] != 0 ) + ; + + try + { + name = new String(data, 0, i, "8859_1"); + } + catch(UnsupportedEncodingException e) + { + name = ""; // shouldn't really happen. + } + if( data[i++] != 0 ) + throw new PNGException("Can't handle nonzero compression types with iCCP chunks."); + try + { + ByteArrayInputStream bos = new ByteArrayInputStream( data, i, + data.length - i ); + profile = ICC_Profile.getInstance( new InflaterInputStream( bos ) ); + } + catch(IOException ioe) + { + throw new PNGException("Couldn't read iCCP profile chunk."); + } + System.out.println("Got profile:"+profile); + } + + public PNGICCProfile( ICC_Profile profile ) + { + super( TYPE_PROFILE ); + this.profile = profile; + byte[] profData = profile.getData(); + byte[] outData = new byte[ profData.length * 2 ]; + Deflater deflater = new Deflater(); + deflater.setInput( profData ); + deflater.finish(); + int n = deflater.deflate( outData ); + data = new byte[ n + 11 + 2 ]; + System.arraycopy(genericName, 0, data, 0, 11 ); + data[11] = data[12] = 0; // null separator and compression type. + // Copy compressed data + System.arraycopy(outData, 0, data, 13, n ); + } + + public ColorSpace getColorSpace() + { + return new ICC_ColorSpace( profile ); + } + + public String toString() + { + return "PNG ICC Profile, name: "+name; + } +} diff --git a/libjava/classpath/gnu/javax/imageio/png/PNGImageReader.java b/libjava/classpath/gnu/javax/imageio/png/PNGImageReader.java new file mode 100644 index 000000000..3209baa26 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/png/PNGImageReader.java @@ -0,0 +1,224 @@ +/* PNGImageReader.java -- The ImageIO ImageReader for PNG + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.imageio.png; + +import gnu.javax.imageio.IIOInputStream; + +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Iterator; + +import javax.imageio.ImageReadParam; +import javax.imageio.ImageReader; +import javax.imageio.ImageTypeSpecifier; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.stream.ImageInputStream; + +/** + * The ImageIO ImageReader for PNG images. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class PNGImageReader + extends ImageReader +{ + + /** + * The PNG file. + */ + private PNGFile pngFile; + + /** + * The decoded image. + */ + private BufferedImage image; + + /** + * The supported image types for PNG. + */ + private ArrayList imageTypes; + + /** + * Creates a new instance. + * + * @param spi the corresponding ImageReaderSpi + */ + public PNGImageReader(PNGImageReaderSpi spi) + { + super(spi); + } + + /** + * Returns the height of the image. + */ + public int getHeight(int imageIndex) + throws IOException + { + checkIndex(imageIndex); + readImage(); + return image.getHeight(); + } + + /** + * Returns the width of the image. + * + * @param imageIndex the index of the image + * + * @return the width of the image + */ + public int getWidth(int imageIndex) throws IOException + { + checkIndex(imageIndex); + readImage(); + return image.getWidth(); + } + + /** + * Returns the image types for the image. + * + * @see ImageReader#getImageTypes(int) + */ + public Iterator getImageTypes(int imageIndex) + throws IOException + { + checkIndex(imageIndex); + readImage(); + if (imageTypes == null) + { + imageTypes = new ArrayList(); + imageTypes.add(new ImageTypeSpecifier(image.getColorModel(), + image.getSampleModel())); + } + return imageTypes.iterator(); + } + + /** + * Returns the number of images in the stream. + * + * @return the number of images in the stream + * + * @see ImageReader#getNumImages(boolean) + */ + public int getNumImages(boolean allowSearch) + throws IOException + { + return 1; + } + + /** + * Reads the image. + * + * @param imageIndex the index of the image to read + * @param param additional parameters + */ + public BufferedImage read(int imageIndex, ImageReadParam param) + throws IOException + { + checkIndex(imageIndex); + readImage(); + return image; + } + + /** + * Sets the input and checks the input parameter. + * + * @see ImageReader#setInput(Object, boolean, boolean) + */ + public void setInput(Object input, + boolean seekForwardOnly, + boolean ignoreMetadata) + { + super.setInput(input, seekForwardOnly, ignoreMetadata); + if (! (input instanceof InputStream || input instanceof ImageInputStream)) + throw new IllegalArgumentException("Input not an ImageInputStream"); + } + + public IIOMetadata getImageMetadata(int imageIndex) + throws IOException + { + // TODO: Not (yet) supported. + checkIndex(imageIndex); + return null; + } + + public IIOMetadata getStreamMetadata() + throws IOException + { + // TODO: Not (yet) supported. + return null; + } + + /** + * Checks the image indexa and throws and IndexOutOfBoundsException if + * appropriate. + * + * @param index the index to check + */ + private void checkIndex(int index) + { + if (index > 0) + throw new IndexOutOfBoundsException("Image index out of bounds"); + } + + /** + * Makes sure that the image is read. + * + * @throws IOException if something goes wrong + */ + private void readImage() + throws IOException + { + if (pngFile == null) + { + if (input instanceof InputStream) + pngFile = new PNGFile((InputStream) input); + else if (input instanceof ImageInputStream) + pngFile = new PNGFile(new IIOInputStream((ImageInputStream) input)); + else + assert false : "Must not happen"; + } + + if (pngFile != null && image == null) + { + image = pngFile.getBufferedImage(); + } + } +} diff --git a/libjava/classpath/gnu/javax/imageio/png/PNGImageReaderSpi.java b/libjava/classpath/gnu/javax/imageio/png/PNGImageReaderSpi.java new file mode 100644 index 000000000..0092ab558 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/png/PNGImageReaderSpi.java @@ -0,0 +1,128 @@ +/* PNGImageReaderSpi.java -- The ImageReader service provider for PNG + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.imageio.png; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Locale; + +import javax.imageio.ImageReader; +import javax.imageio.spi.ImageReaderSpi; +import javax.imageio.stream.ImageInputStream; + +/** + * The ImageIO ImageReader service provider for PNG images. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class PNGImageReaderSpi + extends ImageReaderSpi +{ + + /** + * The PNG file signature. + */ + private static final byte[] SIGNATURE = new byte[] + { (byte) 137, 80, 78, 71, 13, 10, 26, 10 }; + + private static final String VENDOR_NAME = "GNU"; + static final String VERSION = "1.0"; + static final String READER_CLASSNAME = + "gnu.javax.imageio.png.PNGImageReader"; + static final String[] NAMES = { "Portable Network Graphics" }; + static final String[] SUFFIXES = { ".png" , ".PNG" }; + static final String[] MIME_TYPES = { "image/png" }; + static final String[] WRITER_SPI_NAMES = + new String[] { "gnu.javax.imageio.png.PNGWriterSpi" }; + static final Class[] INPUT_TYPES = new Class[]{ InputStream.class, + ImageInputStream.class}; + public PNGImageReaderSpi() + { + super(VENDOR_NAME, VERSION, NAMES, SUFFIXES, MIME_TYPES, READER_CLASSNAME, + INPUT_TYPES, WRITER_SPI_NAMES, false, null, null, null, null, false, + null, null, null, null); + } + + /** + * Determines if the PNG ImageReader can decode the specified input. + * + * @param source the source to decode + */ + public boolean canDecodeInput(Object source) throws IOException + { + boolean canDecode = false; + if (source instanceof ImageInputStream) + { + ImageInputStream in = (ImageInputStream) source; + in.mark(); + canDecode = true; + for (int i = 0; i < SIGNATURE.length && canDecode; i++) + { + byte sig = (byte) in.read(); + if (sig != SIGNATURE[i]) { + canDecode = false; + } + } + in.reset(); + } + return canDecode; + } + + /** + * Returns a new PNGImageReader instance. + * + * @param extension the extension, ignored + */ + public ImageReader createReaderInstance(Object extension) + throws IOException + { + return new PNGImageReader(this); + } + + /** + * Returns a description. + * + * @param locale the locale + */ + public String getDescription(Locale locale) + { + return "Portable Network Graphics"; + } + +} diff --git a/libjava/classpath/gnu/javax/imageio/png/PNGPalette.java b/libjava/classpath/gnu/javax/imageio/png/PNGPalette.java new file mode 100644 index 000000000..197cad846 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/png/PNGPalette.java @@ -0,0 +1,127 @@ +/* PNGPalette.java -- + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.png; + +import java.awt.color.ColorSpace; +import java.awt.image.IndexColorModel; + +/** + * A PNG Palette chunk. + */ +public class PNGPalette extends PNGChunk +{ + private int[] red,green,blue; + + protected PNGPalette( int type, byte[] data, int crc ) throws PNGException + { + super( type, data, crc ); + double l = data.length; + l /= 3.0; + // Check if it's divisible by 3. (Yuck.) + if( l - Math.floor(l) != 0.0 ) + throw new PNGException("Invalid size of palette chunk."); + int nEntries = (int)l; + + red = new int[ nEntries ]; + green = new int[ nEntries ]; + blue = new int[ nEntries ]; + for( int i = 0; i < nEntries; i++ ) + { + red[i] = (data[ i * 3 ] & 0xFF); + green[i] = (data[ i * 3 + 1 ] & 0xFF); + blue[i] = (data[ i * 3 + 2] & 0xFF); + } + } + + public PNGPalette( IndexColorModel cm ) + { + super( TYPE_PALETTE ); + int n = cm.getMapSize(); + data = new byte[ n * 3 ]; + red = new int[ n ]; + green = new int[ n ]; + blue = new int[ n ]; + for(int i = 0; i < n; i++ ) + { + red[i] = data[i * 3] = (byte)cm.getRed(i); + green[i] = data[i * 3 + 1] = (byte)cm.getGreen(i); + blue[i] = data[i * 3 + 2] = (byte)cm.getBlue(i); + } + } + + public IndexColorModel getPalette( ColorSpace cs ) + { + int nc = red.length; + byte[] r = new byte[nc]; + byte[] g = new byte[nc]; + byte[] b = new byte[nc]; + + if( cs == null ) + { + for(int i = 0; i < nc; i ++ ) + { + r[i] = (byte)red[i]; + g[i] = (byte)green[i]; + b[i] = (byte)blue[i]; + } + } + else + { + for(int i = 0; i < nc; i ++ ) + { + float[] in = new float[3]; + in[0] = (((float)red[i]) / 255f); + in[1] = (((float)green[i]) / 255f); + in[2] = (((float)blue[i]) / 255f); + float[] out = cs.toRGB( in ); + r[i] = (byte)( Math.round(out[0] * 255.0) ); + g[i] = (byte)( Math.round(out[1] * 255.0) ); + b[i] = (byte)( Math.round(out[2] * 255.0) ); + } + } + return new IndexColorModel(8, nc, r, g, b); + } + + public String toString() + { + String s = "PNG Palette:\n"; + for( int i = 0; i < red.length; i++) + s = s + "Index " + i + ": ["+ red[i] +", "+green[i]+", "+blue[i]+"]\n"; + return s; + } +} diff --git a/libjava/classpath/gnu/javax/imageio/png/PNGPhys.java b/libjava/classpath/gnu/javax/imageio/png/PNGPhys.java new file mode 100644 index 000000000..d15f09e88 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/png/PNGPhys.java @@ -0,0 +1,112 @@ +/* PNGPhys.java -- + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.png; + +/** + * A PNG "pHYS" chunk - pixel physical dimensions + */ +public class PNGPhys extends PNGChunk +{ + long x, y; + double ratio; + boolean usesRatio; + + protected PNGPhys( int type, byte[] data, int crc ) throws PNGException + { + super( type, data, crc ); + if( data.length < 9 ) + throw new PNGException("Unexpected size of pHYS chunk."); + x = ((data[0] & 0xFF) << 24) | ( (data[1] & 0xFF) << 16 ) | + ((data[2] & 0xFF) << 8) | (data[3] & 0xFF); + y = ((data[4] & 0xFF) << 24) | ( (data[5] & 0xFF) << 16 ) | + ((data[6] & 0xFF) << 8) | (data[7] & 0xFF); + if(data[8] == 0) + { + ratio = ((double)x)/((double)y); + usesRatio = true; + } + } + + public PNGPhys( double ratio ) + { + super( TYPE_PHYS ); + + this.ratio = ratio; + usesRatio = true; + + if( ratio < 1.0 ) + { + y = 0xFFFFFFFF; + x = (long)(0xFFFFFFFFL * ratio); + } + else + { + x = 0xFFFFFFFF; + y = (long)(0xFFFFFFFFL * ratio); + } + makeData(); + } + + public PNGPhys( int x, int y ) + { + super( TYPE_PHYS ); + usesRatio = false; + this.x = x; + this.y = y; + makeData(); + } + + private void makeData() + { + data = new byte[ 9 ]; + byte[] a = getInt( (int)x ); + byte[] b = getInt( (int)y ); + data[0] = a[0]; data[1] = a[1]; data[2] = a[2]; data[3] = a[3]; + data[4] = b[0]; data[5] = b[1]; data[6] = b[2]; data[7] = b[3]; + data[7] = (usesRatio) ? 0 : (byte)0xFF; + } + + public String toString() + { + String s = "PNG Physical pixel size chunk."; + if( usesRatio ) + return s + " Aspect ratio (x/y): " + ratio; + else + return s + " " + x + " by " + y + " pixels per meter. (x, y)."; + } +} diff --git a/libjava/classpath/gnu/javax/imageio/png/PNGTime.java b/libjava/classpath/gnu/javax/imageio/png/PNGTime.java new file mode 100644 index 000000000..824f06f83 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/png/PNGTime.java @@ -0,0 +1,83 @@ +/* PNGTime.java -- + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.imageio.png; + +import java.util.Date; + +/** + * A PNG tIME chunk. + */ +public class PNGTime extends PNGChunk +{ + private Date date; + + protected PNGTime( int type, byte[] data, int crc ) throws PNGException + { + super( type, data, crc ); + if( data.length < 7 ) + throw new PNGException("Unexpectedly short time chunk. ("+data.length+" bytes)"); + + // PNG value is absolute (2006, not 106 or 06), java is from 1900. + int year = ( (data[0] & 0xFF) << 8 ) | (data[1] & 0xFF); + int month = (data[2] & 0xFF); // java counts from 0. PNG from 1. + int day = (data[3] & 0xFF); + int hour = (data[4] & 0xFF); + int minute = (data[5] & 0xFF); + int second = (data[6] & 0xFF); + date = new Date( year - 1900, month - 1, day, hour, minute, second ); + } + + public PNGTime( Date d ) + { + super( TYPE_TIME ); + data = new byte[ 7 ]; + int tmp = d.getYear() + 1900; + data[0] = (byte)((tmp & 0xFF00) >> 8); + data[1] = (byte)(tmp & 0x00FF); + data[2] = (byte)(d.getMonth() + 1); + data[3] = (byte)(d.getDay()); + data[4] = (byte)(d.getHours()); + data[5] = (byte)(d.getMinutes()); + data[6] = (byte)(d.getSeconds()); + } + + public String toString() + { + return "PNG Time chunk: "+date; + } +} diff --git a/libjava/classpath/gnu/javax/management/ListenerData.java b/libjava/classpath/gnu/javax/management/ListenerData.java new file mode 100644 index 000000000..31fdeccf0 --- /dev/null +++ b/libjava/classpath/gnu/javax/management/ListenerData.java @@ -0,0 +1,136 @@ +/* ListenerData.java - Class to contain data about management bean listeners + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.management; + +import javax.management.NotificationFilter; +import javax.management.NotificationListener; + +/** + * Container for data on management listeners. Wraps + * a {@link javax.management.NotificationListener}, + * {@link javax.management.NotificationFilter} and + * passback object in one class. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class ListenerData +{ + /** + * The listener itself. + */ + private NotificationListener listener; + + /** + * A filter to apply to incoming events. + */ + private NotificationFilter filter; + + /** + * An object to pass back to the listener on an + * event occurring. + */ + private Object passback; + + /** + * Constructs a new {@link ListenerData} with the specified + * listener, filter and passback object. + * + * @param listener the listener itself. + * @param filter the filter for incoming events. + * @param passback the object to passback on an incoming event. + */ + public ListenerData(NotificationListener listener, + NotificationFilter filter, Object passback) + { + this.listener = listener; + this.filter = filter; + this.passback = passback; + } + + /** + * Returns the listener. + * + * @return the listener. + */ + public NotificationListener getListener() + { + return listener; + } + + /** + * Returns the filter. + * + * @return the filter. + */ + public NotificationFilter getFilter() + { + return filter; + } + + /** + * Returns the passback object. + * + * @return the passback object. + */ + public Object getPassback() + { + return passback; + } + + /** + * Returns true if the supplied object is an instance of + * {@link ListenerData} and has the same listener, filter + * and passback object. + * + * @param obj the object to check. + * @return true if obj is equal to this. + */ + public boolean equals(Object obj) + { + if (obj instanceof ListenerData) + { + ListenerData data = (ListenerData) obj; + return (data.getListener() == listener && + data.getFilter() == filter && + data.getPassback() == passback); + } + return false; + } + +} diff --git a/libjava/classpath/gnu/javax/management/Server.java b/libjava/classpath/gnu/javax/management/Server.java new file mode 100644 index 000000000..50252d4dd --- /dev/null +++ b/libjava/classpath/gnu/javax/management/Server.java @@ -0,0 +1,2233 @@ +/* Server.java -- A GNU Classpath management server. + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.management; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectStreamClass; +import java.io.StreamCorruptedException; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.ConcurrentHashMap; + +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.AttributeNotFoundException; +import javax.management.BadAttributeValueExpException; +import javax.management.BadBinaryOpValueExpException; +import javax.management.BadStringOperationException; +import javax.management.DynamicMBean; +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.IntrospectionException; +import javax.management.InvalidApplicationException; +import javax.management.InvalidAttributeValueException; +import javax.management.ListenerNotFoundException; +import javax.management.MalformedObjectNameException; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanPermission; +import javax.management.MBeanRegistration; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.MBeanServerDelegate; +import javax.management.MBeanServerNotification; +import javax.management.MBeanTrustPermission; +import javax.management.NotCompliantMBeanException; +import javax.management.Notification; +import javax.management.NotificationBroadcaster; +import javax.management.NotificationEmitter; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.OperationsException; +import javax.management.QueryExp; +import javax.management.ReflectionException; +import javax.management.RuntimeOperationsException; +import javax.management.StandardMBean; + +import javax.management.loading.ClassLoaderRepository; + +/** + * This class provides an {@link javax.management.MBeanServer} + * implementation for GNU Classpath. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class Server + implements MBeanServer +{ + + /** + * The name of the delegate bean. + */ + private static final ObjectName DELEGATE_NAME; + + /** + * The registered beans, represented as a map of + * {@link javax.management.ObjectName}s to + * {@link gnu.javax.management.Server.ServerInfo}s. + */ + private final ConcurrentHashMap beans = + new ConcurrentHashMap(); + + /** + * The default domain. + */ + private final String defaultDomain; + + /** + * The outer server. + */ + private final MBeanServer outer; + + /** + * The class loader repository. + */ + private ClassLoaderRepository repository; + + /** + * The map of listener delegates to the true + * listener. We wrap this in an inner class + * to delay initialisation until a listener + * is actually added. + */ + private static class LazyListenersHolder + { + private static final Map listeners = + new ConcurrentHashMap(); + } + + /** + * An MBean that emits notifications when an MBean is registered and + * unregistered with this server. + * + */ + private final MBeanServerDelegate delegate; + + /** + * Provides sequencing for notifications about registrations. + */ + private static final AtomicLong sequenceNumber = new AtomicLong(1); + + /** + * Initialise the delegate name. + */ + static + { + try + { + DELEGATE_NAME = + new ObjectName("JMImplementation:type=MBeanServerDelegate"); + } + catch (MalformedObjectNameException e) + { + throw (Error) + (new InternalError("Failed to construct " + + "the delegate's object name.").initCause(e)); + } + } + + /** + * Constructs a new management server using the specified + * default domain, delegate bean and outer server. + * + * @param defaultDomain the default domain to use for beans constructed + * with no specified domain. + * @param outer an {@link javax.management.MBeanServer} to pass + * to beans implementing the {@link MBeanRegistration} + * interface, or null if this + * should be passed. + * @param delegate the delegate bean for this server. + */ + public Server(String defaultDomain, MBeanServer outer, + MBeanServerDelegate delegate) + { + this.defaultDomain = defaultDomain; + this.outer = outer; + this.delegate = delegate; + try + { + registerMBean(delegate, DELEGATE_NAME); + } + catch (InstanceAlreadyExistsException e) + { + throw (Error) + (new InternalError("The delegate bean is " + + "already registered.").initCause(e)); + } + catch (MBeanRegistrationException e) + { + throw (Error) + (new InternalError("The delegate bean's preRegister " + + "methods threw an exception.").initCause(e)); + } + catch (NotCompliantMBeanException e) + { + throw (Error) + (new InternalError("The delegate bean is " + + "not compliant.").initCause(e)); + } + } + + /** + * Checks for the necessary security privileges to perform an + * operation. + * + * @param name the name of the bean being accessed. + * @param member the name of the operation or attribute being + * accessed, or null if one is not + * involved. + * @param action the action being performed. + * @throws SecurityException if the action is denied. + */ + private void checkSecurity(ObjectName name, String member, + String action) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + try + { + MBeanInfo info = null; + if (name != null) + { + Object bean = getBean(name); + Method method = bean.getClass().getMethod("getMBeanInfo"); + info = (MBeanInfo) method.invoke(bean); + } + sm.checkPermission(new MBeanPermission((info == null) ? + null : info.getClassName(), + member, name, action)); + } + catch (InstanceNotFoundException e) + { + throw (Error) + (new InternalError("Failed to get bean.").initCause(e)); + } + catch (NoSuchMethodException e) + { + throw (Error) + (new InternalError("Failed to get bean info.").initCause(e)); + } + catch (IllegalAccessException e) + { + throw (Error) + (new InternalError("Failed to get bean info.").initCause(e)); + } + catch (IllegalArgumentException e) + { + throw (Error) + (new InternalError("Failed to get bean info.").initCause(e)); + } + catch (InvocationTargetException e) + { + throw (Error) + (new InternalError("Failed to get bean info.").initCause(e)); + } + } + + /** + * Retrieves the specified bean. + * + * @param name the name of the bean. + * @return the bean. + * @throws InstanceNotFoundException if the name of the management bean + * could not be resolved. + */ + private Object getBean(ObjectName name) + throws InstanceNotFoundException + { + ServerInfo bean = beans.get(name); + if (bean == null) + throw new InstanceNotFoundException("The bean, " + name + + ", was not found."); + return bean.getObject(); + } + + /** + * Registers the supplied listener with the specified management + * bean. Notifications emitted by the management bean are forwarded + * to the listener via the server, which will convert an MBean + * references in the source to a portable {@link ObjectName} + * instance. The notification is otherwise unchanged. + * + * @param name the name of the management bean with which the listener + * should be registered. + * @param listener the listener which will handle notifications from + * the bean. + * @param filter the filter to apply to incoming notifications, or + * null if no filtering should be applied. + * @param passback an object to be passed to the listener when a + * notification is emitted. + * @throws InstanceNotFoundException if the name of the management bean + * could not be resolved. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, name, + * "addNotificationListener")}. + * @see #removeNotificationListener(ObjectName, NotificationListener) + * @see #removeNotificationListener(ObjectName, NotificationListener, + * NotificationFilter, Object) + * @see NotificationBroadcaster#addNotificationListener(NotificationListener, + * NotificationFilter, + * Object) + */ + public void addNotificationListener(ObjectName name, NotificationListener listener, + NotificationFilter filter, Object passback) + throws InstanceNotFoundException + { + Object bean = getBean(name); + checkSecurity(name, null, "addNotificationListener"); + if (bean instanceof NotificationBroadcaster) + { + NotificationBroadcaster bbean = (NotificationBroadcaster) bean; + NotificationListener indirection = new ServerNotificationListener(bean, name, + listener); + bbean.addNotificationListener(indirection, filter, passback); + LazyListenersHolder.listeners.put(listener, indirection); + } + } + + /** + *

+ * Registers the supplied listener with the specified management + * bean. Notifications emitted by the management bean are forwarded + * to the listener via the server, which will convert any MBean + * references in the source to portable {@link ObjectName} + * instances. The notification is otherwise unchanged. + *

+ *

+ * The listener that receives notifications will be the one that is + * registered with the given name at the time this method is called. + * Even if it later unregisters and ceases to use that name, it will + * still receive notifications. + *

+ * + * @param name the name of the management bean with which the listener + * should be registered. + * @param listener the name of the listener which will handle + * notifications from the bean. + * @param filter the filter to apply to incoming notifications, or + * null if no filtering should be applied. + * @param passback an object to be passed to the listener when a + * notification is emitted. + * @throws InstanceNotFoundException if the name of the management bean + * could not be resolved. + * @throws RuntimeOperationsException if the bean associated with the given + * object name is not a + * {@link NotificationListener}. This + * exception wraps an + * {@link IllegalArgumentException}. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, name, + * "addNotificationListener")}. + * @see #removeNotificationListener(ObjectName, NotificationListener) + * @see #removeNotificationListener(ObjectName, NotificationListener, + * NotificationFilter, Object) + * @see NotificationBroadcaster#addNotificationListener(NotificationListener, + * NotificationFilter, + * Object) + */ + public void addNotificationListener(ObjectName name, ObjectName listener, + NotificationFilter filter, Object passback) + throws InstanceNotFoundException + { + Object lbean = getBean(listener); + if (!(lbean instanceof NotificationListener)) + { + RuntimeException e = + new IllegalArgumentException("The supplied listener name does not " + + "correspond to a notification listener."); + throw new RuntimeOperationsException(e); + } + addNotificationListener(name, ((NotificationListener) lbean), filter, passback); + } + + /** + *

+ * Instantiates a new instance of the specified management bean + * using the default constructor and registers it with the server + * under the supplied name. The class is loaded using the + * {@link javax.management.loading.ClassLoaderRepository default + * loader repository} of the server. + *

+ *

+ * If the name supplied is null, then the bean is + * expected to implement the {@link MBeanRegistration} interface. + * The {@link MBeanRegistration#preRegister preRegister} method + * of this interface will be used to obtain the name in this case. + *

+ *

+ * This method is equivalent to calling {@link + * #createMBean(String, ObjectName, Object[], String[]) + * createMBean(className, name, (Object[]) null, + * (String[]) null)} with null parameters + * and signature. + *

+ * + * @param className the class of the management bean, of which + * an instance should be created. + * @param name the name to register the new bean with. + * @return an {@link ObjectInstance} containing the {@link ObjectName} + * and Java class name of the created instance. + * @throws ReflectionException if an exception occurs in creating + * an instance of the bean. + * @throws InstanceAlreadyExistsException if a matching instance + * already exists. + * @throws MBeanRegistrationException if an exception occurs in + * calling the preRegister + * method. + * @throws MBeanException if the bean's constructor throws an exception. + * @throws NotCompliantMBeanException if the created bean is not + * compliant with the JMX specification. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null class name or object + * name or if the object name is a pattern. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply the + * use of the instantiate + * and registerMBean methods. + * @see #createMBean(String, ObjectName, Object[], String[]) + */ + public ObjectInstance createMBean(String className, ObjectName name) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException + { + return createMBean(className, name, (Object[]) null, (String[]) null); + } + + /** + *

+ * Instantiates a new instance of the specified management bean + * using the given constructor and registers it with the server + * under the supplied name. The class is loaded using the + * {@link javax.management.loading.ClassLoaderRepository default + * loader repository} of the server. + *

+ *

+ * If the name supplied is null, then the bean is + * expected to implement the {@link MBeanRegistration} interface. + * The {@link MBeanRegistration#preRegister preRegister} method + * of this interface will be used to obtain the name in this case. + *

+ * + * @param className the class of the management bean, of which + * an instance should be created. + * @param name the name to register the new bean with. + * @param params the parameters for the bean's constructor. + * @param sig the signature of the constructor to use. + * @return an {@link ObjectInstance} containing the {@link ObjectName} + * and Java class name of the created instance. + * @throws ReflectionException if an exception occurs in creating + * an instance of the bean. + * @throws InstanceAlreadyExistsException if a matching instance + * already exists. + * @throws MBeanRegistrationException if an exception occurs in + * calling the preRegister + * method. + * @throws MBeanException if the bean's constructor throws an exception. + * @throws NotCompliantMBeanException if the created bean is not + * compliant with the JMX specification. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null class name or object + * name or if the object name is a pattern. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply the + * use of the instantiate + * and registerMBean methods. + */ + public ObjectInstance createMBean(String className, ObjectName name, + Object[] params, String[] sig) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException + { + return registerMBean(instantiate(className, params, sig), name); + } + + /** + *

+ * Instantiates a new instance of the specified management bean + * using the default constructor and registers it with the server + * under the supplied name. The class is loaded using the + * given class loader. If this argument is null, + * then the same class loader as was used to load the server + * is used. + *

+ *

+ * If the name supplied is null, then the bean is + * expected to implement the {@link MBeanRegistration} interface. + * The {@link MBeanRegistration#preRegister preRegister} method + * of this interface will be used to obtain the name in this case. + *

+ *

+ * This method is equivalent to calling {@link + * #createMBean(String, ObjectName, ObjectName, Object[], String) + * createMBean(className, name, loaderName, (Object[]) null, + * (String) null)} with null parameters + * and signature. + *

+ * + * @param className the class of the management bean, of which + * an instance should be created. + * @param name the name to register the new bean with. + * @param loaderName the name of the class loader. + * @return an {@link ObjectInstance} containing the {@link ObjectName} + * and Java class name of the created instance. + * @throws ReflectionException if an exception occurs in creating + * an instance of the bean. + * @throws InstanceAlreadyExistsException if a matching instance + * already exists. + * @throws MBeanRegistrationException if an exception occurs in + * calling the preRegister + * method. + * @throws MBeanException if the bean's constructor throws an exception. + * @throws NotCompliantMBeanException if the created bean is not + * compliant with the JMX specification. + * @throws InstanceNotFoundException if the specified class loader is not + * registered with the server. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null class name or object + * name or if the object name is a pattern. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply the + * use of the instantiate + * and registerMBean methods. + * @see #createMBean(String, ObjectName, ObjectName, Object[], String[]) + */ + public ObjectInstance createMBean(String className, ObjectName name, + ObjectName loaderName) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException + { + return createMBean(className, name, loaderName, (Object[]) null, + (String[]) null); + } + + /** + *

+ * Instantiates a new instance of the specified management bean + * using the given constructor and registers it with the server + * under the supplied name. The class is loaded using the + * given class loader. If this argument is null, + * then the same class loader as was used to load the server + * is used. + *

+ *

+ * If the name supplied is null, then the bean is + * expected to implement the {@link MBeanRegistration} interface. + * The {@link MBeanRegistration#preRegister preRegister} method + * of this interface will be used to obtain the name in this case. + *

+ * + * @param className the class of the management bean, of which + * an instance should be created. + * @param name the name to register the new bean with. + * @param loaderName the name of the class loader. + * @param params the parameters for the bean's constructor. + * @param sig the signature of the constructor to use. + * @return an {@link ObjectInstance} containing the {@link ObjectName} + * and Java class name of the created instance. + * @throws ReflectionException if an exception occurs in creating + * an instance of the bean. + * @throws InstanceAlreadyExistsException if a matching instance + * already exists. + * @throws MBeanRegistrationException if an exception occurs in + * calling the preRegister + * method. + * @throws MBeanException if the bean's constructor throws an exception. + * @throws NotCompliantMBeanException if the created bean is not + * compliant with the JMX specification. + * @throws InstanceNotFoundException if the specified class loader is not + * registered with the server. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null class name or object + * name or if the object name is a pattern. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply the + * use of the instantiate + * and registerMBean methods. + */ + public ObjectInstance createMBean(String className, ObjectName name, + ObjectName loaderName, Object[] params, + String[] sig) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException + { + return registerMBean(instantiate(className, loaderName, params, sig), + name); + } + + /** + * Deserializes a byte array using the class loader of the specified + * management bean as its context. + * + * @param name the name of the bean whose class loader should be used. + * @param data the byte array to be deserialized. + * @return the deserialized object stream. + * @deprecated {@link #getClassLoaderFor(ObjectName)} should be used + * to obtain the class loader of the bean, which can then + * be used to perform deserialization in the user's code. + * @throws InstanceNotFoundException if the specified bean is not + * registered with the server. + * @throws OperationsException if any I/O error is thrown by the + * deserialization process. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, name, + * "getClassLoaderFor") + */ + public ObjectInputStream deserialize(ObjectName name, byte[] data) + throws InstanceNotFoundException, OperationsException + { + try + { + return new ServerInputStream(new ByteArrayInputStream(data), + getClassLoaderFor(name)); + } + catch (IOException e) + { + throw new OperationsException("An I/O error occurred: " + e); + } + } + + /** + * Deserializes a byte array using the same class loader for its context + * as was used to load the given class. This class loader is obtained by + * loading the specified class using the {@link + * javax.management.loading.ClassLoaderRepository Class Loader Repository} + * and then using the class loader of the resulting {@link Class} instance. + * + * @param name the name of the class which should be loaded to obtain the + * class loader. + * @param data the byte array to be deserialized. + * @return the deserialized object stream. + * @deprecated {@link #getClassLoaderRepository} should be used + * to obtain the class loading repository, which can then + * be used to obtain the {@link Class} instance and deserialize + * the array using its class loader. + * @throws OperationsException if any I/O error is thrown by the + * deserialization process. + * @throws ReflectionException if an error occurs in obtaining the + * {@link Class} instance. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(null, null, null, + * "getClassLoaderRepository") + */ + public ObjectInputStream deserialize(String name, byte[] data) + throws OperationsException, ReflectionException + { + try + { + Class c = getClassLoaderRepository().loadClass(name); + return new ServerInputStream(new ByteArrayInputStream(data), + c.getClassLoader()); + } + catch (IOException e) + { + throw new OperationsException("An I/O error occurred: " + e); + } + catch (ClassNotFoundException e) + { + throw new ReflectionException(e, "The class could not be found."); + } + } + + /** + * Deserializes a byte array using the same class loader for its context + * as was used to load the given class. The name of the class loader to + * be used is supplied, and may be null if the server's + * class loader should be used instead. + * + * @param name the name of the class which should be loaded to obtain the + * class loader. + * @param loader the name of the class loader to use, or null + * if the class loader of the server should be used. + * @param data the byte array to be deserialized. + * @return the deserialized object stream. + * @deprecated {@link #getClassLoader(ObjectName} can be used to obtain + * the named class loader and deserialize the array. + * @throws InstanceNotFoundException if the specified class loader is not + * registered with the server. + * @throws OperationsException if any I/O error is thrown by the + * deserialization process. + * @throws ReflectionException if an error occurs in obtaining the + * {@link Class} instance. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, loader, + * "getClassLoader") + */ + public ObjectInputStream deserialize(String name, ObjectName loader, byte[] data) + throws InstanceNotFoundException, ReflectionException, + OperationsException + { + try + { + Class c = getClassLoader(loader).loadClass(name); + return new ServerInputStream(new ByteArrayInputStream(data), + c.getClassLoader()); + } + catch (IOException e) + { + throw new OperationsException("An I/O error occurred: " + e); + } + catch (ClassNotFoundException e) + { + throw new ReflectionException(e, "The class could not be found."); + } + } + + /** + * Returns the value of the supplied attribute from the specified + * management bean. + * + * @param bean the bean to retrieve the value from. + * @param name the name of the attribute to retrieve. + * @return the value of the attribute. + * @throws AttributeNotFoundException if the attribute could not be + * accessed from the bean. + * @throws MBeanException if the management bean's accessor throws + * an exception. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws ReflectionException if an exception was thrown in trying + * to invoke the bean's accessor. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null bean or attribute + * name. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, name, bean, + * "getAttribute")}. + * @see DynamicMBean#getAttribute(String) + */ + public Object getAttribute(ObjectName bean, String name) + throws MBeanException, AttributeNotFoundException, + InstanceNotFoundException, ReflectionException + { + if (bean == null || name == null) + { + RuntimeException e = + new IllegalArgumentException("One of the supplied arguments was null."); + throw new RuntimeOperationsException(e); + } + Object abean = getBean(bean); + checkSecurity(bean, name, "getAttribute"); + if (abean instanceof DynamicMBean) + return ((DynamicMBean) abean).getAttribute(name); + else + try + { + return new StandardMBean(abean, null).getAttribute(name); + } + catch (NotCompliantMBeanException e) + { + throw (Error) + (new InternalError("Failed to create dynamic bean.").initCause(e)); + } + } + + + /** + * Returns the values of the named attributes from the specified + * management bean. + * + * @param bean the bean to retrieve the value from. + * @param names the names of the attributes to retrieve. + * @return the values of the attributes. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws ReflectionException if an exception was thrown in trying + * to invoke the bean's accessor. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null bean or attribute + * name. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, bean, + * "getAttribute")}. Additionally, + * for an attribute name, n, the + * caller's permission must imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, n, bean, + * "getAttribute")} or that attribute will + * not be included. + * + * @see DynamicMBean#getAttributes(String[]) + */ + public AttributeList getAttributes(ObjectName bean, String[] names) + throws InstanceNotFoundException, ReflectionException + { + if (bean == null || names == null) + { + RuntimeException e = + new IllegalArgumentException("One of the supplied arguments was null."); + throw new RuntimeOperationsException(e); + } + Object abean = getBean(bean); + checkSecurity(bean, null, "getAttribute"); + AttributeList list = new AttributeList(names.length); + for (int a = 0; a < names.length; ++a) + { + if (names[a] == null) + { + RuntimeException e = + new IllegalArgumentException("Argument " + a + " was null."); + throw new RuntimeOperationsException(e); + } + checkSecurity(bean, names[a], "getAttribute"); + try + { + Object value; + if (abean instanceof DynamicMBean) + value = ((DynamicMBean) abean).getAttribute(names[a]); + else + try + { + value = new StandardMBean(abean, null).getAttribute(names[a]); + } + catch (NotCompliantMBeanException e) + { + throw (Error) + (new InternalError("Failed to create dynamic bean.").initCause(e)); + } + list.add(new Attribute(names[a], value)); + } + catch (AttributeNotFoundException e) + { + /* Ignored */ + } + catch (MBeanException e) + { + /* Ignored */ + } + } + return list; + } + + + /** + * Returns the specified class loader. If the specified value is + * null, then the class loader of the server will be + * returned. If l is the requested class loader, + * and r is the actual class loader returned, then + * either l and r will be identical, + * or they will at least return the same class from + * {@link ClassLoader#loadClass(String)} for any given string. + * They may not be identical due to one or the other + * being wrapped in another class loader (e.g. for security). + * + * @param name the name of the class loader to return. + * @return the class loader. + * @throws InstanceNotFoundException if the class loader can not + * be found. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, name, + * "getClassLoader") + */ + public ClassLoader getClassLoader(ObjectName name) + throws InstanceNotFoundException + { + if (name == null) + { + checkSecurity(null, null, "getClassLoader"); + return getClass().getClassLoader(); + } + Object bean = getBean(name); + checkSecurity(name, null, "getClassLoader"); + return (ClassLoader) bean; + } + + /** + * Returns the class loader of the specified management bean. If + * l is the requested class loader, and r + * is the actual class loader returned, then either l + * and r will be identical, or they will at least + * return the same class from {@link ClassLoader#loadClass(String)} + * for any given string. They may not be identical due to one or + * the other being wrapped in another class loader (e.g. for + * security). + * + * @param name the name of the bean whose class loader should be + * returned. + * @return the class loader. + * @throws InstanceNotFoundException if the bean is not registered + * with the server. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, name, + * "getClassLoaderFor") + */ + public ClassLoader getClassLoaderFor(ObjectName name) + throws InstanceNotFoundException + { + Object bean = getBean(name); + checkSecurity(name, null, "getClassLoaderFor"); + return bean.getClass().getClassLoader(); + } + + /** + * Returns the class loader repository used by this server. + * + * @return the class loader repository. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(null, null, null, + * "getClassLoaderRepository") + */ + public ClassLoaderRepository getClassLoaderRepository() + { + return repository; + } + + /** + * Returns the default domain this server applies to beans that have + * no specified domain. + * + * @return the default domain. + */ + public String getDefaultDomain() + { + return defaultDomain; + } + + /** + * Returns an array containing all the domains used by beans registered + * with this server. The ordering of the array is undefined. + * + * @return the list of domains. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(null, null, name, + * "getDomains")}. Additionally, + * for an domain, d, the + * caller's permission must imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(null, null, + * new ObjectName("d:x=x"), "getDomains")} + * or that domain will not be included. Note + * that "x=x" is an arbitrary key-value pair + * provided to satisfy the constructor. + * @see ObjectName#getDomain() + */ + public String[] getDomains() + { + checkSecurity(null, null, "getDomains"); + Set domains = new HashSet(); + Iterator iterator = beans.keySet().iterator(); + while (iterator.hasNext()) + { + String d = iterator.next().getDomain(); + try + { + checkSecurity(new ObjectName(d + ":x=x"), null, "getDomains"); + domains.add(d); + } + catch (MalformedObjectNameException e) + { + /* Ignored */ + } + } + return domains.toArray(new String[domains.size()]); + } + + /** + * Returns the number of management beans registered with this server. + * This may be less than the real number if the caller's access is + * restricted. + * + * @return the number of registered beans. + */ + public Integer getMBeanCount() + { + return Integer.valueOf(beans.size()); + } + + /** + * Returns information on the given management bean. + * + * @param name the name of the management bean. + * @return an instance of {@link MBeanInfo} for the bean. + * @throws IntrospectionException if an exception occurs in examining + * the bean. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws ReflectionException if an exception occurs when trying + * to invoke {@link DynamicMBean#getMBeanInfo()} + * on the bean. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, name, + * "getMBeanInfo")}. + * @see DynamicMBean#getMBeanInfo() + */ + public MBeanInfo getMBeanInfo(ObjectName name) + throws InstanceNotFoundException, IntrospectionException, + ReflectionException + { + Object bean = getBean(name); + checkSecurity(name, null, "getMBeanInfo"); + try + { + Method method = bean.getClass().getMethod("getMBeanInfo"); + return (MBeanInfo) method.invoke(bean); + } + catch (NoSuchMethodException e) + { + try + { + return new StandardMBean(bean, null).getMBeanInfo(); + } + catch (NotCompliantMBeanException ex) + { + throw new IntrospectionException("An error occurred in executing " + + "getMBeanInfo on the bean: " + ex + "."); + } + } + catch (IllegalAccessException e) + { + throw new ReflectionException(e, "Failed to call getMBeanInfo"); + } + catch (IllegalArgumentException e) + { + throw new ReflectionException(e, "Failed to call getMBeanInfo"); + } + catch (InvocationTargetException e) + { + throw new ReflectionException(e, "The method threw an exception"); + } + } + + /** + * Returns the {@link ObjectInstance} created for the specified + * management bean on registration. + * + * @param name the name of the bean. + * @return the corresponding {@link ObjectInstance} instance. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, name, + * "getObjectInstance") + * @see #createMBean(String, ObjectName) + */ + public ObjectInstance getObjectInstance(ObjectName name) + throws InstanceNotFoundException + { + ServerInfo bean = beans.get(name); + if (bean == null) + throw new InstanceNotFoundException("The bean, " + name + + ", was not found."); + return bean.getInstance(); + } + + /** + *

+ * Creates an instance of the specified class using the list of + * class loaders from the {@link + * javax.management.loading.ClassLoaderRepository Class Loader + * Repository}. The class should have a public constructor + * with no arguments. A reference to the new instance is returned, + * but the instance is not yet registered with the server. + *

+ *

+ * This method is equivalent to calling {@link + * #instantiate(String, Object[], String[]) + * instantiate(name, (Object[]) null, (String[]) null)} + * with null parameters and signature. + *

+ * + * @param name the name of the class of bean to be instantiated. + * @return an instance of the given class. + * @throws ReflectionException if an exception is thrown during + * loading the class or calling the + * constructor. + * @throws MBeanException if the constructor throws an exception. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null name. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, null, + * "instantiate")}. + * @see #instantiate(String, Object[], String[]) + */ + public Object instantiate(String name) + throws ReflectionException, MBeanException + { + return instantiate(name, (Object[]) null, (String[]) null); + } + + /** + * Creates an instance of the specified class using the list of + * class loaders from the {@link + * javax.management.loading.ClassLoaderRepository Class Loader + * Repository}. The class should have a public constructor + * matching the supplied signature. A reference to the new + * instance is returned, but the instance is not yet + * registered with the server. + * + * @param name the name of the class of bean to be instantiated. + * @param params the parameters for the constructor. + * @param sig the signature of the constructor. + * @return an instance of the given class. + * @throws ReflectionException if an exception is thrown during + * loading the class or calling the + * constructor. + * @throws MBeanException if the constructor throws an exception. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null name. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, null, + * "instantiate")}. + */ + public Object instantiate(String name, Object[] params, String[] sig) + throws ReflectionException, MBeanException + { + checkSecurity(null, null, "instantiate"); + if (name == null) + { + RuntimeException e = + new IllegalArgumentException("The name was null."); + throw new RuntimeOperationsException(e); + } + Class[] sigTypes = new Class[sig.length]; + for (int a = 0; a < sigTypes.length; ++a) + { + try + { + sigTypes[a] = repository.loadClass(sig[a]); + } + catch (ClassNotFoundException e) + { + throw new ReflectionException(e, "The class, " + sigTypes[a] + + ", in the method signature " + + "could not be loaded."); + } + } + try + { + Constructor cons = + repository.loadClass(name).getConstructor(sigTypes); + return cons.newInstance(params); + } + catch (ClassNotFoundException e) + { + throw new ReflectionException(e, "The class, " + name + + ", of the constructor " + + "could not be loaded."); + } + catch (NoSuchMethodException e) + { + throw new ReflectionException(e, "The method, " + name + + ", could not be found."); + } + catch (IllegalAccessException e) + { + throw new ReflectionException(e, "Failed to instantiate the object"); + } + catch (InstantiationException e) + { + throw new ReflectionException(e, "Failed to instantiate the object"); + } + catch (InvocationTargetException e) + { + throw new MBeanException((Exception) e.getCause(), "The constructor " + + name + " threw an exception"); + } + } + + /** + *

+ * Creates an instance of the specified class using the supplied + * class loader. If the class loader given is null, + * then the class loader of the server will be used. The class + * should have a public constructor with no arguments. A reference + * to the new instance is returned, but the instance is not yet + * registered with the server. + *

+ *

+ * This method is equivalent to calling {@link + * #instantiate(String, ObjectName, Object[], String[]) + * instantiate(name, loaderName, (Object[]) null, + * (String[]) null)} with null parameters + * and signature. + *

+ * + * @param name the name of the class of bean to be instantiated. + * @param loaderName the name of the class loader to use. + * @return an instance of the given class. + * @throws InstanceNotFoundException if the class loader is not + * registered with the server. + * @throws ReflectionException if an exception is thrown during + * loading the class or calling the + * constructor. + * @throws MBeanException if the constructor throws an exception. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null name. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, null, + * "instantiate")}. + * @see #instantiate(String, Object[], String[]) + */ + public Object instantiate(String name, ObjectName loaderName) + throws InstanceNotFoundException, ReflectionException, + MBeanException + { + return instantiate(name, loaderName); + } + + /** + * Creates an instance of the specified class using the supplied + * class loader. If the class loader given is null, + * then the class loader of the server will be used. The class + * should have a public constructor matching the supplied + * signature. A reference to the new instance is returned, + * but the instance is not yet registered with the server. + * + * @param name the name of the class of bean to be instantiated. + * @param loaderName the name of the class loader to use. + * @param params the parameters for the constructor. + * @param sig the signature of the constructor. + * @return an instance of the given class. + * @throws InstanceNotFoundException if the class loader is not + * registered with the server. + * @throws ReflectionException if an exception is thrown during + * loading the class or calling the + * constructor. + * @throws MBeanException if the constructor throws an exception. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null name. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, null, + * "instantiate")}. + */ + public Object instantiate(String name, ObjectName loaderName, + Object[] params, String[] sig) + throws InstanceNotFoundException, ReflectionException, + MBeanException + { + checkSecurity(null, null, "instantiate"); + if (name == null) + { + RuntimeException e = + new IllegalArgumentException("The name was null."); + throw new RuntimeOperationsException(e); + } + ClassLoader loader = getClassLoader(loaderName); + Class[] sigTypes = new Class[sig.length]; + for (int a = 0; a < sig.length; ++a) + { + try + { + sigTypes[a] = Class.forName(sig[a], true, loader); + } + catch (ClassNotFoundException e) + { + throw new ReflectionException(e, "The class, " + sig[a] + + ", in the method signature " + + "could not be loaded."); + } + } + try + { + Constructor cons = + Class.forName(name, true, loader).getConstructor(sigTypes); + return cons.newInstance(params); + } + catch (ClassNotFoundException e) + { + throw new ReflectionException(e, "The class, " + name + + ", of the constructor " + + "could not be loaded."); + } + catch (NoSuchMethodException e) + { + throw new ReflectionException(e, "The method, " + name + + ", could not be found."); + } + catch (IllegalAccessException e) + { + throw new ReflectionException(e, "Failed to instantiate the object"); + } + catch (InstantiationException e) + { + throw new ReflectionException(e, "Failed to instantiate the object"); + } + catch (InvocationTargetException e) + { + throw new MBeanException((Exception) e.getCause(), "The constructor " + + name + " threw an exception"); + } + } + + /** + * Invokes the supplied operation on the specified management + * bean. The class objects specified in the signature are loaded + * using the same class loader as was used for the management bean. + * + * @param bean the management bean whose operation should be invoked. + * @param name the name of the operation to invoke. + * @param params the parameters of the operation. + * @param sig the signature of the operation. + * @return the return value of the method. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws MBeanException if the method invoked throws an exception. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null name. + * @throws ReflectionException if an exception is thrown in invoking the + * method. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, name, bean, + * "invoke")}. + * @see DynamicMBean#invoke(String, Object[], String[]) + */ + public Object invoke(ObjectName bean, String name, Object[] params, String[] sig) + throws InstanceNotFoundException, MBeanException, + ReflectionException + { + if (bean == null) + { + RuntimeException e = + new IllegalArgumentException("The bean was null."); + throw new RuntimeOperationsException(e); + } + Object abean = getBean(bean); + checkSecurity(bean, name, "invoke"); + if (abean instanceof DynamicMBean) + return ((DynamicMBean) abean).invoke(name, params, sig); + else + try + { + return new StandardMBean(abean, null).invoke(name, params, sig); + } + catch (NotCompliantMBeanException e) + { + throw (Error) + (new InternalError("Failed to create dynamic bean.").initCause(e)); + } + } + + /** + *

+ * Returns true if the specified management bean is an instance + * of the supplied class. + *

+ *

+ * A bean, B, is an instance of a class, C, if either of the following + * conditions holds: + *

+ *
    + *
  • The class name in B's {@link MBeanInfo} is equal to the supplied + * name.
  • + *
  • Both the class of B and C were loaded by the same class loader, + * and B is assignable to C.
  • + *
+ * + * @param name the name of the management bean. + * @param className the name of the class to test if name is + * an instance of. + * @return true if either B is directly an instance of the named class, + * or B is assignable to the class, given that both it and B's + * current class were loaded using the same class loader. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, name, + * "isInstanceOf") + */ + public boolean isInstanceOf(ObjectName name, String className) + throws InstanceNotFoundException + { + Object bean = getBean(name); + checkSecurity(name, null, "isInstanceOf"); + MBeanInfo info; + if (bean instanceof DynamicMBean) + info = ((DynamicMBean) bean).getMBeanInfo(); + else + try + { + info = new StandardMBean(bean, null).getMBeanInfo(); + } + catch (NotCompliantMBeanException e) + { + throw (Error) + (new InternalError("Failed to create dynamic bean.").initCause(e)); + } + if (info.getClassName().equals(className)) + return true; + Class bclass = bean.getClass(); + try + { + Class oclass = Class.forName(className); + return (bclass.getClassLoader().equals(oclass.getClassLoader()) && + oclass.isAssignableFrom(bclass)); + } + catch (ClassNotFoundException e) + { + return false; + } + } + + /** + * Returns true if the specified management bean is registered with + * the server. + * + * @param name the name of the management bean. + * @return true if the bean is registered. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null bean name. + */ + public boolean isRegistered(ObjectName name) + { + if (name == null) + { + RuntimeException e = + new IllegalArgumentException("The name was null."); + throw new RuntimeOperationsException(e); + } + return beans.containsKey(name); + } + + /** + *

+ * Returns a set of {@link ObjectInstance}s matching the specified + * criteria. The full set of beans registered with the server + * are passed through two filters: + *

+ *
    + *
  1. Pattern matching is performed using the supplied + * {@link ObjectName}.
  2. + *
  3. The supplied query expression is applied.
  4. + *
+ *

+ * If both the object name and the query expression are null, + * or the object name has no domain and no key properties, + * no filtering will be performed and all beans are returned. + *

+ * + * @param name an {@link ObjectName} to use as a filter. + * @param query a query expression to apply to each of the beans that match + * the given object name. + * @return a set of {@link ObjectInstance}s matching the filtered beans. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(null, null, name, + * "queryMBeans")}. Additionally, + * for an bean, b, the + * caller's permission must imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, b, name, + * "queryMBeans")} or that bean will + * not be included. Such an exception may also + * arise from the execution of the query, in which + * case that particular bean will again be excluded. + */ + public Set queryMBeans(ObjectName name, QueryExp query) + { + checkSecurity(name, null, "queryMBeans"); + Set results = new HashSet(); + for (Map.Entry entry : beans.entrySet()) + { + ObjectName nextName = entry.getKey(); + checkSecurity(name, nextName.toString(), "queryMBeans"); + try + { + if ((name == null || name.apply(nextName)) && + (query == null || query.apply(nextName))) + results.add(entry.getValue().getInstance()); + } + catch (BadStringOperationException e) + { + /* Ignored -- assume false result */ + } + catch (BadBinaryOpValueExpException e) + { + /* Ignored -- assume false result */ + } + catch (BadAttributeValueExpException e) + { + /* Ignored -- assume false result */ + } + catch (InvalidApplicationException e) + { + /* Ignored -- assume false result */ + } + } + return results; + } + + /** + *

+ * Returns a set of {@link ObjectName}s matching the specified + * criteria. The full set of beans registered with the server + * are passed through two filters: + *

+ *
    + *
  1. Pattern matching is performed using the supplied + * {@link ObjectName}.
  2. + *
  3. The supplied query expression is applied.
  4. + *
+ *

+ * If both the object name and the query expression are null, + * or the object name has no domain and no key properties, + * no filtering will be performed and all beans are returned. + *

+ * + * @param name an {@link ObjectName} to use as a filter. + * @param query a query expression to apply to each of the beans that match + * the given object name. + * @return a set of {@link ObjectName}s matching the filtered beans. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(null, null, name, + * "queryNames")}. Additionally, + * for an name, n, the + * caller's permission must imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, n, name, + * "queryNames")} or that name will + * not be included. Such an exception may also + * arise from the execution of the query, in which + * case that particular bean will again be excluded. + * Note that these permissions are implied if the + * queryMBeans permissions are available. + */ + public Set queryNames(ObjectName name, QueryExp query) + { + checkSecurity(name, null, "queryNames"); + Set results = new HashSet(); + for (ObjectName nextName : beans.keySet()) + { + checkSecurity(name, nextName.toString(), "queryNames"); + try + { + if ((name == null || name.apply(nextName)) && + (query == null || query.apply(nextName))) + results.add(nextName); + } + catch (BadStringOperationException e) + { + /* Ignored -- assume false result */ + } + catch (BadBinaryOpValueExpException e) + { + /* Ignored -- assume false result */ + } + catch (BadAttributeValueExpException e) + { + /* Ignored -- assume false result */ + } + catch (InvalidApplicationException e) + { + /* Ignored -- assume false result */ + } + } + return results; + } + + /** + * Registers the supplied instance with the server, using the specified + * {@link ObjectName}. If the name given is null, then + * the bean supplied is expected to implement the {@link MBeanRegistration} + * interface and provide the name via the + * {@link MBeanRegistration#preRegister preRegister} method + * of this interface. + * + * @param obj the object to register with the server. + * @param name the name under which to register the object, + * or null if the {@link MBeanRegistration} + * interface should be used. + * @return an {@link ObjectInstance} containing the supplied + * {@link ObjectName} along with the name of the bean's class. + * @throws InstanceAlreadyExistsException if a matching instance + * already exists. + * @throws MBeanRegistrationException if an exception occurs in + * calling the preRegister + * method. + * @throws NotCompliantMBeanException if the created bean is not + * compliant with the JMX specification. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null object. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, name, + * "registerMBean")}. className + * here corresponds to the result of + * {@link MBeanInfo#getClassName()} for objects of + * this class. If this check succeeds, a check + * is also made on its + * {@link java.security.ProtectionDomain} to ensure + * it implies {@link MBeanTrustPermission(String) + * MBeanTrustPermission("register")}. + * The use of the {@link MBeanRegistration} interface + * results in another {@link MBeanPermission} check + * being made on the returned {@link ObjectName}. + */ + public ObjectInstance registerMBean(Object obj, ObjectName name) + throws InstanceAlreadyExistsException, MBeanRegistrationException, + NotCompliantMBeanException + { + SecurityManager sm = System.getSecurityManager(); + Class cl = obj.getClass(); + String className = cl.getName(); + if (sm != null) + { + sm.checkPermission(new MBeanPermission(className, null, name, + "registerMBean")); + if (!(cl.getProtectionDomain().implies(new MBeanTrustPermission("register")))) + throw new SecurityException("The protection domain of the object's class" + + "does not imply the trust permission," + + "register"); + } + if (obj == null) + { + RuntimeException e = + new IllegalArgumentException("The object was null."); + throw new RuntimeOperationsException(e); + } + MBeanRegistration register = null; + if (obj instanceof MBeanRegistration) + register = (MBeanRegistration) obj; + if (name == null && register == null) + { + RuntimeException e = + new IllegalArgumentException("The name was null and " + + "the bean does not implement " + + "MBeanRegistration."); + throw new RuntimeOperationsException(e); + } + if (register != null) + { + try + { + name = register.preRegister(this, name); + if (name == null) + { + RuntimeException e = + new NullPointerException("The name returned by " + + "MBeanRegistration.preRegister() " + + "was null"); + throw e; + } + if (sm != null) + sm.checkPermission(new MBeanPermission(className, null, name, + "registerMBean")); + } + catch (SecurityException e) + { + register.postRegister(Boolean.FALSE); + throw e; + } + catch (Exception e) + { + register.postRegister(Boolean.FALSE); + throw new MBeanRegistrationException(e, "Pre-registration failed."); + } + } + ObjectInstance obji = new ObjectInstance(name, className); + if (beans.putIfAbsent(name, new ServerInfo(obji, obj)) != null) + { + if (register != null) + register.postRegister(Boolean.FALSE); + throw new InstanceAlreadyExistsException(name + "is already registered."); + } + if (register != null) + register.postRegister(Boolean.TRUE); + notify(name, MBeanServerNotification.REGISTRATION_NOTIFICATION); + return obji; + } + + /** + * Removes the specified listener from the list of recipients + * of notifications from the supplied bean. This includes all + * combinations of filters and passback objects registered for + * this listener. For more specific removal of listeners, see + * {@link #removeNotificationListener(ObjectName, + * NotificationListener,NotificationFilter,Object)} + * + * @param name the name of the management bean from which the + * listener should be removed. + * @param listener the listener to remove. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws ListenerNotFoundException if the specified listener + * is not registered with the bean. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, name, + * "removeNotificationListener")}. + * @see #addNotificationListener(NotificationListener, NotificationFilter, + * java.lang.Object) + * @see NotificationBroadcaster#removeNotificationListener(NotificationListener) + */ + public void removeNotificationListener(ObjectName name, + NotificationListener listener) + throws InstanceNotFoundException, ListenerNotFoundException + { + Object bean = getBean(name); + checkSecurity(name, null, "removeNotificationListener"); + if (bean instanceof NotificationBroadcaster) + { + NotificationBroadcaster bbean = (NotificationBroadcaster) bean; + bbean.removeNotificationListener(listener); + LazyListenersHolder.listeners.remove(listener); + } + } + + /** + * Removes the specified listener from the list of recipients + * of notifications from the supplied bean. Only the first instance with + * the supplied filter and passback object is removed. + * null is used as a valid value for these parameters, + * rather than as a way to remove all registration instances for + * the specified listener; for this behaviour instead, see + * {@link #removeNotificationListener(ObjectName, NotificationListener)}. + * + * @param name the name of the management bean from which the + * listener should be removed. + * @param listener the listener to remove. + * @param filter the filter of the listener to remove. + * @param passback the passback object of the listener to remove. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws ListenerNotFoundException if the specified listener + * is not registered with the bean. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, name, + * "removeNotificationListener")}. + * @see #addNotificationListener(ObjectName, NotificationListener, + * NotificationFilter, Object) + * @see NotificationEmitter#removeNotificationListener(NotificationListener, + * NotificationFilter, + * Object) + */ + public void removeNotificationListener(ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object passback) + throws InstanceNotFoundException, ListenerNotFoundException + { + Object bean = getBean(name); + checkSecurity(name, null, "removeNotificationListener"); + if (bean instanceof NotificationEmitter) + { + NotificationEmitter bbean = (NotificationEmitter) bean; + bbean.removeNotificationListener(listener, filter, passback); + LazyListenersHolder.listeners.remove(listener); + } + } + + /** + * Removes the specified listener from the list of recipients + * of notifications from the supplied bean. This includes all + * combinations of filters and passback objects registered for + * this listener. For more specific removal of listeners, see + * {@link #removeNotificationListener(ObjectName, + * ObjectName,NotificationFilter,Object)} + * + * @param name the name of the management bean from which the + * listener should be removed. + * @param listener the name of the listener to remove. + * @throws InstanceNotFoundException if a name doesn't match a registered + * bean. + * @throws ListenerNotFoundException if the specified listener + * is not registered with the bean. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, name, + * "removeNotificationListener")}. + * @see #addNotificationListener(NotificationListener, NotificationFilter, + * java.lang.Object) + * @see NotificationBroadcaster#removeNotificationListener(NotificationListener) + */ + public void removeNotificationListener(ObjectName name, ObjectName listener) + throws InstanceNotFoundException, ListenerNotFoundException + { + Object lbean = getBean(listener); + if (!(lbean instanceof NotificationListener)) + { + RuntimeException e = + new IllegalArgumentException("The supplied listener name does not " + + "correspond to a notification listener."); + throw new RuntimeOperationsException(e); + } + removeNotificationListener(name, ((NotificationListener) lbean)); + } + + /** + * Removes the specified listener from the list of recipients + * of notifications from the supplied bean. Only the first instance with + * the supplied filter and passback object is removed. + * null is used as a valid value for these parameters, + * rather than as a way to remove all registration instances for + * the specified listener; for this behaviour instead, see + * {@link #removeNotificationListener(ObjectName, ObjectName)}. + * + * @param name the name of the management bean from which the + * listener should be removed. + * @param listener the name of the listener to remove. + * @param filter the filter of the listener to remove. + * @param passback the passback object of the listener to remove. + * @throws InstanceNotFoundException if a name doesn't match a registered + * bean. + * @throws ListenerNotFoundException if the specified listener + * is not registered with the bean. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, name, + * "removeNotificationListener")}. + * @see #addNotificationListener(ObjectName, NotificationListener, + * NotificationFilter, Object) + * @see NotificationEmitter#removeNotificationListener(NotificationListener, + * NotificationFilter, + * Object) + */ + public void removeNotificationListener(ObjectName name, + ObjectName listener, + NotificationFilter filter, + Object passback) + throws InstanceNotFoundException, ListenerNotFoundException + { + Object lbean = getBean(listener); + if (!(lbean instanceof NotificationListener)) + { + RuntimeException e = + new IllegalArgumentException("The supplied listener name does not " + + "correspond to a notification listener."); + throw new RuntimeOperationsException(e); + } + removeNotificationListener(name, ((NotificationListener) lbean), filter, + passback); + } + + /** + * Sets the value of the specified attribute of the supplied + * management bean. + * + * @param name the name of the management bean. + * @param attribute the attribute to set. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws AttributeNotFoundException if the attribute does not + * correspond to an attribute + * of the bean. + * @throws InvalidAttributeValueException if the value is invalid + * for this particular + * attribute of the bean. + * @throws MBeanException if setting the attribute causes + * the bean to throw an exception (which + * becomes the cause of this exception). + * @throws ReflectionException if an exception occurred in trying + * to use the reflection interface + * to lookup the attribute. The + * thrown exception is the cause of + * this exception. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null bean or attribute + * name. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, name, bean, + * "setAttribute")}. + * @see #getAttribute(ObjectName, String) + * @see DynamicMBean#setAttribute(Attribute) + */ + public void setAttribute(ObjectName name, Attribute attribute) + throws InstanceNotFoundException, AttributeNotFoundException, + InvalidAttributeValueException, MBeanException, + ReflectionException + { + if (attribute == null || name == null) + { + RuntimeException e = + new IllegalArgumentException("One of the supplied arguments was null."); + throw new RuntimeOperationsException(e); + } + Object bean = getBean(name); + checkSecurity(name, attribute.getName(), "setAttribute"); + if (bean instanceof DynamicMBean) + ((DynamicMBean) bean).setAttribute(attribute); + else + try + { + new StandardMBean(bean, null).setAttribute(attribute); + } + catch (NotCompliantMBeanException e) + { + throw (Error) + (new InternalError("Failed to create dynamic bean.").initCause(e)); + } + } + + /** + * Sets the value of each of the specified attributes + * of the supplied management bean to that specified by + * the {@link Attribute} object. The returned list contains + * the attributes that were set and their new values. + * + * @param name the name of the management bean. + * @param attributes the attributes to set. + * @return a list of the changed attributes. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws ReflectionException if an exception occurred in trying + * to use the reflection interface + * to lookup the attribute. The + * thrown exception is the cause of + * this exception. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null bean or attribute + * list. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, bean, + * "setAttribute")}. Additionally, + * for an attribute name, n, the + * caller's permission must imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, n, bean, + * "setAttribute")} or that attribute will + * not be included. + * @see #getAttributes(ObjectName, String[]) + * @see DynamicMBean#setAttributes(AttributeList) + */ + public AttributeList setAttributes(ObjectName name, AttributeList attributes) + throws InstanceNotFoundException, ReflectionException + { + if (name == null || attributes == null) + { + RuntimeException e = + new IllegalArgumentException("One of the supplied arguments was null."); + throw new RuntimeOperationsException(e); + } + Object abean = getBean(name); + checkSecurity(name, null, "setAttribute"); + AttributeList list = new AttributeList(attributes.size()); + Iterator it = attributes.iterator(); + while (it.hasNext()) + { + try + { + Attribute attrib = (Attribute) it.next(); + if (attrib == null) + { + RuntimeException e = + new IllegalArgumentException("An attribute was null."); + throw new RuntimeOperationsException(e); + } + checkSecurity(name, attrib.getName(), "setAttribute"); + if (abean instanceof DynamicMBean) + ((DynamicMBean) abean).setAttribute(attrib); + else + try + { + new StandardMBean(abean, null).setAttribute(attrib); + } + catch (NotCompliantMBeanException e) + { + throw (Error) + (new InternalError("Failed to create dynamic bean.").initCause(e)); + } + list.add(attrib); + } + catch (AttributeNotFoundException e) + { + /* Ignored */ + } + catch (InvalidAttributeValueException e) + { + /* Ignored */ + } + catch (MBeanException e) + { + /* Ignored */ + } + } + return list; + } + + /** + * Unregisters the specified management bean. Following this operation, + * the bean instance is no longer accessible from the server via this + * name. Prior to unregistering the bean, the + * {@link MBeanRegistration#preDeregister()} method will be called if + * the bean implements the {@link MBeanRegistration} interface. + * + * @param name the name of the management bean. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws MBeanRegistrationException if an exception occurs in + * calling the preDeregister + * method. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null bean name or a + * request being made to unregister the + * {@link MBeanServerDelegate} bean. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, name, + * "unregisterMBean")}. + */ + public void unregisterMBean(ObjectName name) + throws InstanceNotFoundException, MBeanRegistrationException + { + if (name == null) + { + RuntimeException e = + new IllegalArgumentException("The name was null."); + throw new RuntimeOperationsException(e); + } + if (name.equals(DELEGATE_NAME)) + { + RuntimeException e = + new IllegalArgumentException("The delegate can not be unregistered."); + throw new RuntimeOperationsException(e); + } + Object bean = getBean(name); + checkSecurity(name, null, "unregisterMBean"); + MBeanRegistration register = null; + if (bean instanceof MBeanRegistration) + { + register = (MBeanRegistration) bean; + try + { + register.preDeregister(); + } + catch (Exception e) + { + throw new MBeanRegistrationException(e, "Pre-deregistration failed."); + } + } + beans.remove(name); + notify(name, MBeanServerNotification.UNREGISTRATION_NOTIFICATION); + if (register != null) + register.postDeregister(); + } + + /** + * Notifies the delegate of beans being registered + * and unregistered. + * + * @param name the bean being registered. + * @param type the type of notification; + * {@code REGISTRATION_NOTIFICATION} or + * {@code UNREGISTRATION_NOTIFICATION}. + */ + private void notify(ObjectName name, String type) + { + delegate.sendNotification + (new MBeanServerNotification + (type, DELEGATE_NAME, sequenceNumber.getAndIncrement(), name)); + } + + /** + * Input stream which deserializes using the given classloader. + */ + private class ServerInputStream + extends ObjectInputStream + { + + private ClassLoader cl; + + public ServerInputStream(InputStream is, ClassLoader cl) + throws IOException, StreamCorruptedException + { + super(is); + this.cl = cl; + } + + protected Class resolveClass(ObjectStreamClass osc) + throws ClassNotFoundException, IOException + { + try + { + return Class.forName(osc.getName(), true, cl); + } + catch (ClassNotFoundException e) + { + return super.resolveClass(osc); + } + } + + } + + /** + * Holder for information on registered beans. + */ + private class ServerInfo + { + private ObjectInstance instance; + + private Object object; + + public ServerInfo(ObjectInstance instance, Object object) + { + this.instance = instance; + this.object = object; + } + + public Object getObject() + { + return object; + } + + public ObjectInstance getInstance() + { + return instance; + } + } + + /** + * Notification listener which removes direct references + * to beans. + */ + private class ServerNotificationListener + implements NotificationListener + { + + /** + * The bean from which notifications are emitted. + */ + Object bean; + + /** + * The {@link ObjectName} of the emitting bean. + */ + ObjectName name; + + /** + * The real {@link NotificationListener}. + */ + NotificationListener listener; + + /** + * Constructs a new {@link ServerNotificationListener} replacing + * occurrences of bean with its name. + * + * @param bean the bean emitting notifications. + * @param name the object name of the emitting bean. + * @param listener the listener events eventually reach. + */ + public ServerNotificationListener(Object bean, ObjectName name, + NotificationListener listener) + { + this.bean = bean; + this.name = name; + this.listener = listener; + } + + /** + * Replace a direct reference to bean with its + * object reference, if necessary, before calling the listener. + * + * @param notif the notification being emitted. + * @param handback an object that will be returned to the notification + * listener when an event occurs. + */ + public void handleNotification(Notification notif, Object handback) + { + if (notif.getSource() == bean) + notif.setSource(name); + listener.handleNotification(notif, handback); + } + + } + +} diff --git a/libjava/classpath/gnu/javax/management/Translator.java b/libjava/classpath/gnu/javax/management/Translator.java new file mode 100644 index 000000000..38d575aca --- /dev/null +++ b/libjava/classpath/gnu/javax/management/Translator.java @@ -0,0 +1,550 @@ +/* Translator.java -- Performs MXBean data type translation. + Copyright (C) 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.management; + +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Proxy; +import java.lang.reflect.Type; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; +import java.util.SortedSet; + +import javax.management.JMX; +import javax.management.MBeanServerInvocationHandler; + +import javax.management.openmbean.ArrayType; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenMBeanParameterInfo; +import javax.management.openmbean.OpenMBeanParameterInfoSupport; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; + +/** + * Translates Java data types to their equivalent + * open data type, and vice versa, according to the + * {@link javax.management.MXBean} rules. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ +public final class Translator +{ + + /** + * Translates the input Java data types to the equivalent + * open data types. + * + * @param jtypes the Java types supplied as parameters. + * @param method the method that was called. + * @return the equivalent open types required by the {@link MXBean}. + * @throws Throwable if an exception is thrown in performing the + * conversion. + */ + public static final Object[] fromJava(Object[] jtypes, Method method) + throws Throwable + { + Type[] gtypes = method.getGenericParameterTypes(); + Object[] otypes = new Object[jtypes.length]; + for (int a = 0; a < jtypes.length; ++a) + otypes[a] = fromJava(jtypes[a], gtypes[a]); + return otypes; + } + + /** + * Translates the input Java data type to the equivalent + * open data type. + * + * @param jtype the Java type supplied as a parameter. + * @param type the type of the parameter. + * @return the equivalent open type required by the {@link MXBean}. + * @throws Throwable if an exception is thrown in performing the + * conversion. + */ + public static final Object fromJava(Object jtype, Type type) + throws Throwable + { + if (jtype == null) + return null; + Class jclass = jtype.getClass(); + if (OpenType.ALLOWED_CLASSNAMES_LIST.contains(jclass.getName())) + return jtype; + if (jclass.isArray()) + { + Class ctype = jclass.getComponentType(); + if (ctype.isPrimitive()) + return jtype; + if (OpenType.ALLOWED_CLASSNAMES_LIST.contains(ctype.getName())) + return jtype; + Object[] elems = (Object[]) jtype; + Object[] celems = new Object[elems.length]; + for (int a = 0; a < elems.length; ++a) + celems[a] = fromJava(elems[a], elems[a].getClass()); + return makeArraySpecific(celems); + } + String tName = getTypeName(type); + if (jtype instanceof List || jtype instanceof Set || + jtype instanceof SortedSet) + { + if (jtype instanceof SortedSet) + { + ParameterizedType ptype = (ParameterizedType) type; + Class elemClass = (Class) ptype.getActualTypeArguments()[0]; + if (!Comparable.class.isAssignableFrom(elemClass)) + throw new IllegalArgumentException(jtype + " has a " + + "non-comparable element " + + "type, " + elemClass); + if (((SortedSet) jtype).comparator() != null) + throw new IllegalArgumentException(jtype + " does not " + + "use natural ordering."); + } + Collection elems = (Collection) jtype; + int numElems = elems.size(); + Object[] celems = new Object[numElems]; + Iterator i = elems.iterator(); + for (int a = 0; a < numElems; ++a) + { + Object elem = i.next(); + celems[a] = fromJava(elem, elem.getClass()); + } + return makeArraySpecific(celems); + } + if (jtype instanceof Enum) + return ((Enum) jtype).name(); + if (jtype instanceof Map || jtype instanceof SortedMap) + { + int lparam = tName.indexOf("<"); + int comma = tName.indexOf(",", lparam); + int rparam = tName.indexOf(">", comma); + String key = tName.substring(lparam + 1, comma).trim(); + String value = tName.substring(comma + 1, rparam).trim(); + String typeName = null; + if (jtype instanceof Map) + typeName = "java.util.Map" + tName.substring(lparam); + else + { + Class keyClass = Class.forName(key); + if (!Comparable.class.isAssignableFrom(keyClass)) + throw new IllegalArgumentException(jtype + " has a " + + "non-comparable element " + + "type, " + keyClass); + if (((SortedMap) jtype).comparator() != null) + throw new IllegalArgumentException(jtype + " does not " + + "use natural ordering."); + typeName = "java.util.SortedMap" + tName.substring(lparam); + } + OpenType k = translate(key).getOpenType(); + OpenType v = translate(value).getOpenType(); + CompositeType rowType = new CompositeType(typeName, typeName, + new String[] { "key", "value" }, + new String[] { "Map key", "Map value"}, + new OpenType[] {k,v}); + TabularType tabType = new TabularType(typeName, typeName, rowType, + new String[]{"key"}); + TabularData data = new TabularDataSupport(tabType); + for (Map.Entry entry : ((Map) jtype).entrySet()) + { + try + { + data.put(new CompositeDataSupport(rowType, + new String[] { + "key", + "value" + }, + new Object[] { + entry.getKey(), + entry.getValue() + })); + } + catch (OpenDataException e) + { + throw (InternalError) (new InternalError("A problem occurred " + + "converting the map " + + "to a composite data " + + "structure.").initCause(e)); + } + } + return data; + } + if (JMX.isMXBeanInterface(jclass)) + { + try + { + MBeanServerInvocationHandler ih = (MBeanServerInvocationHandler) + Proxy.getInvocationHandler(jtype); + return ih.getObjectName(); + } + catch (IllegalArgumentException e) + { + throw new IllegalArgumentException("For a MXBean to be translated " + + "to an open type, it must be a " + + "proxy.", e); + } + catch (ClassCastException e) + { + throw new IllegalArgumentException("For a MXBean to be translated " + + "to an open type, it must have a " + + "MBeanServerInvocationHandler.", e); + } + } + /* FIXME: Handle other types */ + throw new IllegalArgumentException("The type, " + jtype + + ", is not convertible."); + } + + /** + * Translates the returned open data type to the value + * required by the interface. + * + * @param otype the open type returned by the method call. + * @param method the method that was called. + * @return the equivalent return type required by the interface. + * @throws Throwable if an exception is thrown in performing the + * conversion. + */ + public static final Object toJava(Object otype, Method method) + throws Throwable + { + Class returnType = method.getReturnType(); + if (returnType.isEnum()) + { + String ename = (String) otype; + Enum[] constants = (Enum[]) returnType.getEnumConstants(); + for (Enum c : constants) + if (c.name().equals(ename)) + return c; + } + if (List.class.isAssignableFrom(returnType)) + { + Object[] elems = (Object[]) otype; + List l = new ArrayList(elems.length); + for (Object elem : elems) + l.add(elem); + return l; + } + if (Map.class.isAssignableFrom(returnType)) + { + TabularData data = (TabularData) otype; + Map m = new HashMap(data.size()); + for (Object val : data.values()) + { + CompositeData vals = (CompositeData) val; + m.put(vals.get("key"), vals.get("value")); + } + return m; + } + try + { + Method m = returnType.getMethod("from", + new Class[] + { CompositeData.class }); + return m.invoke(null, (CompositeData) otype); + } + catch (NoSuchMethodException e) + { + /* Ignored; we expect this if this + isn't a from(CompositeData) class */ + } + return otype; + } + + /** + * Creates a new array which has the specific type + * used by the elements of the original {@link Object} + * array supplied. + * + * @param arr a series of elements in an {@link Object} + * array. + * @return the same elements in a new array of the specific + * type. + */ + private static final Object[] makeArraySpecific(Object[] arr) + { + Object[] rcelems = (Object[]) Array.newInstance(arr[0].getClass(), + arr.length); + System.arraycopy(arr, 0, rcelems, 0, arr.length); + return rcelems; + } + + /** + * Translates the name of a type into an equivalent + * {@link javax.management.openmbean.OpenMBeanParameterInfo} + * that describes it. + * + * @param type the type to describe. + * @return an instance of + * {@link javax.management.openmbean.OpenMBeanParameterInfo}, + * describing the translated type and limits of the given type. + * @throws OpenDataException if a type is not open. + */ + public static final OpenMBeanParameterInfo translate(String type) + throws OpenDataException + { + if (type.equals("boolean") || type.equals(Boolean.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.BOOLEAN, + null, + new Boolean[] { + Boolean.TRUE, + Boolean.FALSE + }); + if (type.equals("byte") || type.equals(Byte.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.BYTE, + null, + Byte.valueOf(Byte.MIN_VALUE), + Byte.valueOf(Byte.MAX_VALUE)); + if (type.equals("char") || type.equals(Character.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.CHARACTER, + null, + Character.valueOf(Character.MIN_VALUE), + Character.valueOf(Character.MAX_VALUE)); + if (type.equals("double") || type.equals(Double.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.DOUBLE, + null, + Double.valueOf(Double.MIN_VALUE), + Double.valueOf(Double.MAX_VALUE)); + if (type.equals("float") || type.equals(Float.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.FLOAT, + null, + Float.valueOf(Float.MIN_VALUE), + Float.valueOf(Float.MAX_VALUE)); + if (type.equals("int") || type.equals(Integer.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.INTEGER, + null, + Integer.valueOf(Integer.MIN_VALUE), + Integer.valueOf(Integer.MAX_VALUE)); + if (type.equals("long") || type.equals(Long.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.LONG, + null, + Long.valueOf(Long.MIN_VALUE), + Long.valueOf(Long.MAX_VALUE)); + if (type.equals("short") || type.equals(Short.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.SHORT, + null, + Short.valueOf(Short.MIN_VALUE), + Short.valueOf(Short.MAX_VALUE)); + if (type.equals(String.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.STRING); + if (type.equals("void")) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.VOID); + if (type.startsWith("java.util.Map")) + { + int lparam = type.indexOf("<"); + int comma = type.indexOf(",", lparam); + int rparam = type.indexOf(">", comma); + String key = type.substring(lparam + 1, comma).trim(); + OpenType k = translate(key).getOpenType(); + OpenType v = translate(type.substring(comma + 1, rparam).trim()).getOpenType(); + CompositeType ctype = new CompositeType(Map.class.getName(), Map.class.getName(), + new String[] { "key", "value" }, + new String[] { "Map key", "Map value"}, + new OpenType[] { k, v}); + TabularType ttype = new TabularType(key, key, ctype, + new String[] { "key" }); + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + ttype); + } + if (type.startsWith("java.util.List")) + { + int lparam = type.indexOf("<"); + int rparam = type.indexOf(">"); + OpenType e = translate(type.substring(lparam + 1, rparam).trim()).getOpenType(); + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + new ArrayType>(1, e) + ); + } + Class c; + try + { + c = Class.forName(type); + } + catch (ClassNotFoundException e) + { + throw (InternalError) + (new InternalError("The class for a type used in a management bean " + + "could not be loaded.").initCause(e)); + } + if (c.isEnum()) + { + Object[] values = c.getEnumConstants(); + String[] names = new String[values.length]; + for (int a = 0; a < values.length; ++a) + names[a] = values[a].toString(); + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.STRING, + null, names); + } + if (c.isArray()) + { + int depth; + for (depth = 0; c.getName().charAt(depth) == '['; ++depth) + ; + OpenType ot = getTypeFromClass(c.getComponentType()); + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + new ArrayType>(depth, ot) + ); + } + Method[] methods = c.getDeclaredMethods(); + List names = new ArrayList(); + List> types = new ArrayList>(); + for (int a = 0; a < methods.length; ++a) + { + String name = methods[a].getName(); + if (Modifier.isPublic(methods[a].getModifiers())) + { + if (name.startsWith("get")) + { + names.add(name.substring(3)); + types.add(getTypeFromClass(methods[a].getReturnType())); + } + else if (name.startsWith("is")) + { + names.add(name.substring(2)); + types.add(getTypeFromClass(methods[a].getReturnType())); + } + } + } + if (names.isEmpty()) + throw new OpenDataException("The type used does not have an open type translation."); + String[] fields = names.toArray(new String[names.size()]); + CompositeType ctype = new CompositeType(c.getName(), c.getName(), + fields, fields, + types.toArray(new OpenType[types.size()])); + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + ctype); + } + + /** + * Obtains the {@link javax.management.openmbean.OpenType} + * for a particular class. + * + * @param c the class to obtain the type for. + * @return the appropriate instance. + * @throws OpenDataException if the type is not open. + */ + private static final OpenType getTypeFromClass(Class c) + throws OpenDataException + { + return Translator.translate(c.getName()).getOpenType(); + } + + /** + *

+ * Returns the type name according to the rules described + * in {@link javax.management.MXBean}. Namely, for a type, + * {@code T}, {@code typename(T)} is computed as follows: + *

+ *
    + *
  • If T is non-generic and not an array, then the value + * of {@link java.lang.Class#getName()} is returned.
  • + *
  • If T is an array type, {@code{E[]}, then the type name + * is {@code typename(E)} followed by an occurrence + * of {@code '[]'} for each dimension.
  • + *
  • If T is a generic or parameterized type, the type name + * is composed of {@code typename(P)}, where {@code P} is the + * parameterized type name, followed by {@code '<'}, the resulting + * list of type names of the parameters after applying {@code typename} + * to each, separated by commas, and {@code '>'}.
  • + *
+ * + * @param type the type to return the type name of. + * @return the type name computed according to the rules above. + */ + private static final String getTypeName(Type type) + { + if (type instanceof Class) + { + Class c = (Class) type; + if (c.isArray()) + { + StringBuilder b = + new StringBuilder(c.getComponentType().getName()); + String normName = c.getName(); + for (int a = 0; a < normName.length(); ++a) + { + if (normName.charAt(a) == '[') + b.append("[]"); + else + break; + } + return b.toString(); + } + return c.getName(); + } + return type.toString(); + } + +} diff --git a/libjava/classpath/gnu/javax/naming/giop/ContextContinuation.java b/libjava/classpath/gnu/javax/naming/giop/ContextContinuation.java new file mode 100644 index 000000000..e952393cc --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/giop/ContextContinuation.java @@ -0,0 +1,956 @@ +/* ContextContinuation.java -- handles corbaname: urls + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.naming.giop; + +import gnu.CORBA.NamingService.Ext; +import gnu.CORBA.NamingService.NameTransformer; + +import java.util.Hashtable; + +import javax.naming.Binding; +import javax.naming.Context; +import javax.naming.ContextNotEmptyException; +import javax.naming.InvalidNameException; +import javax.naming.Name; +import javax.naming.NameAlreadyBoundException; +import javax.naming.NameClassPair; +import javax.naming.NameNotFoundException; +import javax.naming.NameParser; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.OperationNotSupportedException; +import javax.naming.directory.InvalidAttributesException; + +import org.omg.CORBA.ORB; +import org.omg.CORBA.portable.Delegate; +import org.omg.CORBA.portable.ObjectImpl; +import org.omg.CosNaming.BindingIteratorHolder; +import org.omg.CosNaming.BindingListHolder; +import org.omg.CosNaming.NameComponent; +import org.omg.CosNaming.NamingContext; +import org.omg.CosNaming.NamingContextExt; +import org.omg.CosNaming.NamingContextExtHelper; +import org.omg.CosNaming.NamingContextHelper; +import org.omg.CosNaming._NamingContextExtStub; +import org.omg.CosNaming._NamingContextStub; +import org.omg.CosNaming.NamingContextPackage.AlreadyBound; +import org.omg.CosNaming.NamingContextPackage.CannotProceed; +import org.omg.CosNaming.NamingContextPackage.InvalidName; +import org.omg.CosNaming.NamingContextPackage.NotFound; + +/** + * The context to represent the corba naming service. Being the naming service, + * the returned context supports creating the subcontexts, forwarding this task + * to the existing naming service. When listing bindings, it uses the + * {@link Context#BATCHSIZE} property to determine, how many bindings should + * be returned at once (the process is transparend) + * + * @author Audrius Meskauskas (audriusa@Bioinformatics.org) + */ +public class ContextContinuation implements Context +{ + /** + * This number of bindings will be requested from the naming server at once, + * while the subsequent bindings will be requested via binding iterator one by + * one. Use {@link Context#BATCHSIZE} to override the value of this constant. + */ + public int DEFAULT_BATCH_SIZE = 20; + + /** + * The actual CORBA naming service. + */ + NamingContextExt service; + + /** + * The object request broker, used to access the naming service. This field + * is only initialised when the context is constructed from the URL. + */ + ORB orb; + + /** + * The properties. + */ + Hashtable properties; + + /** + * The parent factory. + */ + GiopNamingServiceFactory factory; + + /** + * The name transformer to obtain the name from its string representation. The + * to_name method of the naming service is avoided as it may be remote and + * hence expensive. The conversion rules are standard and cannot be service + * specific. + */ + static NameTransformer transformer = new NameTransformer(); + + /** + * The batch size for list operations - how many to return at once. + */ + public final int howMany; + + /** + * Creates a new naming context that uses naming service, represented by the + * given CORBA object. + * + * @param nsObject + * the naming service object. It must be possible to narrow it into + * the NamingContextExt. + * @param props + * the environment table. + * @param anOrb + * the associated ORB. This reference is used during cleanup. + * @param aFactory + * parent factory. This reference is used during cleanup. + */ + public ContextContinuation(org.omg.CORBA.Object nsObject, + Hashtable props, ORB anOrb, + GiopNamingServiceFactory aFactory) + { + factory = aFactory; + orb = anOrb; + + Delegate delegate = ((ObjectImpl) nsObject)._get_delegate(); + + // If the IOR provides the IDL ID, we can check if our name + // service is old NamingContext or new NamingContextExt. + // Not all forms of the URL always provide the IDL id. + if (!nsObject._is_a(NamingContextExtHelper.id()) + && nsObject._is_a(NamingContextHelper.id())) + { + // We are surely working with the old version. + _NamingContextStub stub = new _NamingContextStub(); + stub._set_delegate(delegate); + // The Ext object will add the necessary extensions. + service = new Ext(stub); + } + else + { + // We expecte the service to be the NamingContextExt (this is true + // for both Sun's and our implementations). There is no easy way + // to check the version. + _NamingContextExtStub stub = new _NamingContextExtStub(); + stub._set_delegate(delegate); + service = stub; + } + properties = props; + howMany = getBatchSize(); + } + + /** + * Give the specified name for the specified object. The passed name must not + * be already bound to some other object. The components of the name are + * mapped into the components of the CORBA name. + * + * @param name + * the name that will be given to the object (in the scope of this + * context). + * @param obj + * the object being named. + * @throws NameAlreadyBoundException + * if this name is already used to name some object. + * @throws InvalidAttributesException + * if the object does not supply all required attributes. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void bind(Name name, Object obj) throws NamingException + { + try + { + org.omg.CORBA.Object object = (org.omg.CORBA.Object) obj; + service.bind(toGiop(name), object); + } + catch (ClassCastException e) + { + throw new NamingException(org.omg.CORBA.Object.class + " required "); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + catch (AlreadyBound e) + { + throw new NameAlreadyBoundException(); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Give the specified name for the specified object. The passed name must not + * be already bound to some other object. + * + * @param name + * the name that will be given to the object (in the scope of this + * context). + * @param obj + * the object being named. + * @throws NameAlreadyBoundException + * if this name is already used to name some object. + * @throws InvalidAttributesException + * if the object does not supply all required attributes. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void bind(String name, Object obj) throws NamingException + { + try + { + org.omg.CORBA.Object object = (org.omg.CORBA.Object) obj; + service.bind(transformer.toName(name), object); + } + catch (ClassCastException e) + { + throw new NamingException(org.omg.CORBA.Object.class + " required "); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + catch (AlreadyBound e) + { + throw new NameAlreadyBoundException(); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Releases all resources, associated with this context. The close() method + * can be called several times, but after it has been once invoked, it is not + * allowed to call any other method of this context. This method destroys + * the ORB, if we have one. + * + * @throws NamingException + */ + public void close() throws NamingException + { + if (orb != null && factory !=null) + { + factory.checkIfReferenced(orb); + } + } + + /** + * Not supported. + */ + public Name composeName(Name name, Name prefix) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported + */ + public String composeName(String name1, String name2) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Creates the new naming subcontext and binds it to the current (this) + * context. The returned object will wrap around the newly created CORBA + * subcontext + * + * @param subContext + * the name of the new context being created + * @return the newly created context, bound to the instance of the context on + * that the method has been called + * @throws NameAlreadyBoundException + * if this name is already bound + * @throws InvalidAttributesException + * if the creation of the new context requires the missing mandatory + * attributes + * @throws NamingException + */ + public Context createSubcontext(Name subContext) throws NamingException + { + try + { + org.omg.CORBA.Object subcontext = service.bind_new_context( + toGiop(subContext)); + Hashtable clonedProps = new Hashtable(); + clonedProps.putAll(properties); + + // Nulls are passed both for orb and factory, as the child contexts + // need not to do any cleanup. + return new ContextContinuation(subcontext, clonedProps, null, null); + } + catch (AlreadyBound e) + { + throw new NameAlreadyBoundException(); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + catch (Exception ex) + { + throw new NamingException(ex.toString()); + } + } + + /** + * Creates the new naming subcontext and binds it to the current (this) + * context. The returned object will wrap around the newly created CORBA + * subcontext + * + * @param subContext + * the name of the new context being created + * @return the newly created context, bound to the instance of the context on + * that the method has been called + * @throws NameAlreadyBoundException + * if this name is already bound + * @throws InvalidAttributesException + * if the creation of the new context requires the missing mandatory + * attributes + * @throws NamingException + */ + public Context createSubcontext(String subContext) throws NamingException + { + try + { + org.omg.CORBA.Object subcontext = + service.bind_new_context(transformer.toName(subContext)); + Hashtable clonedProps = new Hashtable(); + clonedProps.putAll(properties); + + // Nulls are passed both for orb and factory, as the child contexts + // need not to do any cleanup. + return new ContextContinuation(subcontext, clonedProps, null, + null); + } + catch (AlreadyBound e) + { + throw new NameAlreadyBoundException(subContext); + } + catch (InvalidName e) + { + throw new InvalidNameException(subContext); + } + catch (Exception ex) + { + throw new NamingException(ex.toString()); + } + } + + /** + * Removes the naming subcontext from this naming context. Returns without + * action if such subcontext does not exist. The context being destroyed must + * be empty. + * + * @param subContext + * the name of the subcontext beig removed. + * @throws ContextNotEmptyException + * if the named context is not empty. + * @throws NamingException + */ + public void destroySubcontext(Name subContext) throws NamingException + { + unbind(subContext); + } + + /** + * Removes the naming subcontext from this naming context. Returns without + * action if such subcontext does not exist. The context being destroyed must + * be empty. + * + * @param subContext + * the name of the subcontext beig removed. + * @throws ContextNotEmptyException + * if the named context is not empty. + * @throws NamingException + */ + public void destroySubcontext(String subContext) throws NamingException + { + unbind(subContext); + } + + /** + * Returs the full name of this naming context. The returned string is not a + * JNDI composite name and should not be passed directly to the methods of the + * naming context. This implementation returns the IOR. + * + * @return the full name of this naming context, in its own namespace. + * @throws OperationNotSupportedException + * if the naming system, represented by this context, does not + * support the notation of the full name. + * @throws NamingException + */ + public String getNameInNamespace() throws NamingException + { + if (orb != null) + return orb.object_to_string(service); + else + { + try + { + ObjectImpl impl = (ObjectImpl) service; + return impl._orb().object_to_string(impl); + } + catch (ClassCastException e) + { + throw new UnsupportedOperationException(); + } + } + } + + /** + * Not supported. + */ + public NameParser getNameParser(Name name) throws NamingException + { + throw new UnsupportedOperationException(); + } + + /** + * Not supported. + */ + public NameParser getNameParser(String name) throws NamingException + { + throw new UnsupportedOperationException(); + } + + /** + * Creates and returns the enumeration over the name bindings that are present + * the given subcontext. The enumeration elements have the type of + * {@link NameClassPair}, providing also information about the class of the + * bound object. The behaviour in the case if the bindings are added or + * removed later is not defined. The contents of the subcontexts are not + * included. + * + * @param name + * the name of the subcontext + * @return the enumeration over the names, known for the given subcontext. + * @throws NamingException + */ + public NamingEnumeration list(Name name) throws NamingException + { + BindingIteratorHolder bi = new BindingIteratorHolder(); + BindingListHolder bl = new BindingListHolder(); + + NamingContext subcontext; + + if (name.size() == 0) + subcontext = service; + else + { + try + { + subcontext = (NamingContextHelper.narrow(service.resolve(toGiop(name)))); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + + } + + subcontext.list(howMany, bl, bi); + + return new ListEnumeration(bl, bi, howMany); + } + + /** + * Creates and returns the enumeration over the name bindings that are present + * the given subcontext. The enumeration elements have the type of + * {@link NameClassPair}, providing also information about the class of the + * bound object. The behaviour in the case if the bindings are added or + * removed later is not defined. The contents of the subcontexts are not + * included. + * + * @param name + * the name of the subcontext + * @return the enumeration over the names, known for the given subcontext. + * @throws NamingException + */ + public NamingEnumeration list(String name) throws NamingException + { + BindingIteratorHolder bi = new BindingIteratorHolder(); + BindingListHolder bl = new BindingListHolder(); + + NamingContext subcontext; + + if (name.length() == 0) + subcontext = service; + else + { + try + { + subcontext = (NamingContextHelper.narrow(service.resolve_str(name))); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + + } + + subcontext.list(howMany, bl, bi); + + return new ListEnumeration(bl, bi, howMany); + } + + /** + * Creates and returns the enumeration over the name - object bindings that + * are present the given subcontext. The enumeration elements have the type of + * {@link Binding}, providing also information about the class of the bound + * object. The behaviour in the case if the bindings are added or removed + * later is not defined. The contents of the subcontexts are not included. + * + * @param name + * the name of the subcontext + * @return the enumeration over the names, known for the given subcontext. + * @throws NamingException + */ + public NamingEnumeration listBindings(Name name) throws NamingException + { + BindingIteratorHolder bi = new BindingIteratorHolder(); + BindingListHolder bl = new BindingListHolder(); + + NamingContext subcontext; + + if (name.size() == 0) + subcontext = service; + else + { + try + { + subcontext = (NamingContextHelper.narrow(service.resolve(toGiop(name)))); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + subcontext.list(howMany, bl, bi); + + return new ListBindingsEnumeration(bl, bi, howMany, subcontext); + } + + /** + * Creates and returns the enumeration over the name - object bindings that + * are present the given subcontext. The enumeration elements have the type of + * {@link Binding}, providing also information about the class of the bound + * object. The behaviour in the case if the bindings are added or removed + * later is not defined. The contents of the subcontexts are not included. + * + * @param name + * the name of the subcontext + * @return the enumeration over the names, known for the given subcontext. + * @throws NamingException + */ + public NamingEnumeration listBindings(String name) throws NamingException + { + BindingIteratorHolder bi = new BindingIteratorHolder(); + BindingListHolder bl = new BindingListHolder(); + + NamingContext subcontext; + + if (name.length() == 0) + subcontext = service; + else + { + try + { + subcontext = (NamingContextHelper.narrow(service.resolve_str(name))); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + + } + + subcontext.list(howMany, bl, bi); + + return new ListBindingsEnumeration(bl, bi, howMany, subcontext); + } + + /** + * Gets the previously named object by name. If the passed name is empty, the + * method should return a cloned instance of this naming context. + * + * @param name + * the name of the object being searched in this context + * @return the named object + * @throws NameNotFountException + * if the name is not found + */ + public Object lookup(Name name) throws NamingException + { + try + { + return service.resolve(toGiop(name)); + } + catch (NotFound e) + { + throw new NameNotFoundException(); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Gets the previously named object by name. If the passed name is empty, the + * method should return a cloned instance of this naming context. + * + * @param name + * the name of the object being searched in this context + * @return the named object + * @throws NamingException + * if the naming fails. + */ + public Object lookup(String name) throws NamingException + { + try + { + return service.resolve_str(name); + } + catch (NotFound e) + { + throw new NameNotFoundException(); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Not supported. + */ + public Object lookupLink(Name name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported. + */ + public Object lookupLink(String name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Give the specified name for the specified object. Unlike bind, this method + * silently replaces the existing binding for this name, if one exists. + * + * @param name + * the name that will be given to the object (in the scope of this + * context). + * @param obj + * the object being named. + * @throws InvalidAttributesException + * if the object does not supply all required attributes. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void rebind(Name name, Object obj) throws NamingException + { + try + { + org.omg.CORBA.Object object = (org.omg.CORBA.Object) obj; + service.rebind(toGiop(name), object); + } + catch (ClassCastException e) + { + throw new NamingException(org.omg.CORBA.Object.class + " required "); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Give the specified name for the specified object. Unlike bind, this method + * silently replaces the existing binding for this name, if one exists. + * + * @param name + * the name that will be given to the object (in the scope of this + * context). + * @param obj + * the object being named. + * @throws InvalidAttributesException + * if the object does not supply all required attributes. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void rebind(String name, Object obj) throws NamingException + { + try + { + org.omg.CORBA.Object object = (org.omg.CORBA.Object) obj; + service.rebind(transformer.toName(name), object); + } + catch (ClassCastException e) + { + throw new NamingException(org.omg.CORBA.Object.class + " required "); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Renames the existing binding, removing the existing and giving the new name + * for the same object. + * + * @param oldName + * the existing name of the known object + * @param newName + * the new name of the same object + * @throws NameNotFoundException + * if the oldName is unknown for this context + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void rename(Name oldName, Name newName) throws NamingException + { + Object object = lookup(oldName); + unbind(oldName); + bind(newName, object); + } + + /** + * Renames the existing binding, removing the existing and giving the new name + * for the same object. + * + * @param oldName + * the existing name of the known object + * @param newName + * the new name of the same object + * @throws NameNotFoundException + * if the oldName is unknown for this context + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void rename(String oldName, String newName) throws NamingException + { + Object object = lookup(oldName); + unbind(oldName); + bind(newName, object); + } + + /** + * Removes the name - object mapping from the current context. This method + * returns without action if the name is not bound to an object in the + * terminal context, but throws {@link NameNotFoundException} if one of the + * intermadiate contexts does not exist. + * + * @param name + * the name to be removed + * @throws NameNotFoundException + * if one of the intermediate naming contexts does not exist. Will + * not be thrown if just the terminal binding is missing. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void unbind(Name name) throws NamingException + { + try + { + service.unbind(toGiop(name)); + } + catch (NotFound e) + { + throw new NameNotFoundException(); + } + catch (CannotProceed e) + { + throw new ContextNotEmptyException(); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + } + + /** + * Removes the name - object mapping from the current context. This method + * returns without action if the name is not bound to an object in the + * terminal context, but throws {@link NameNotFoundException} if one of the + * intermadiate contexts does not exist. + * + * @param name + * the name to be removed + * @throws NameNotFoundException + * if one of the intermediate naming contexts does not exist. Will + * not be thrown if just the terminal binding is missing. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void unbind(String name) throws NamingException + { + try + { + service.unbind(transformer.toName(name)); + } + catch (NotFound e) + { + throw new NameNotFoundException(name); + } + catch (CannotProceed e) + { + throw new ContextNotEmptyException(name); + } + catch (InvalidName e) + { + throw new InvalidNameException(name); + } + } + + /** + * Add new environment property to the environment of this context. Both name + * and value of the new property must not be null. If the property is already + * defined, is current value is replaced by the propVal. + * + * @param key + * the name of the new property + * @param value + * the value of the new property + * @return the previous value of this property or null if the property has not + * been previously defined + * @throws NamingException + */ + public Object addToEnvironment(String key, Object value) + throws NamingException + { + if (key == null || value == null) + throw new NullPointerException(); + return properties.put(key, value); + } + + /** + * Returns the environment, associated with this naming context. The returned + * table should never be modified by the caller. Use {@link #addToEnvironment} + * and {@link #removeFromEnvironment} to modify the environement, if needed. + * + * @return the table, representing the environment of this context + * @throws NamingException + */ + public Hashtable getEnvironment() throws NamingException + { + return properties; + } + + /** + * Removes the property with the given name from the environment. Returns + * without action if this property is not defined. + * + * @param propName + * the name of the property being removed. + * @return the value of the property that has been removed or null if the + * property was not defined. + * @throws NamingException + */ + public Object removeFromEnvironment(String propName) throws NamingException + { + return properties.remove(propName); + } + + /** + * Convert the {@link Name} into array of the name components, required to the + * CORBA naming service. First the string representation is obtained, then + * it is converted using parsing rules of the CORBA name. + * + * @param name + * then name to convert + * @return the converted array of components. + */ + public NameComponent[] toGiop(Name name) throws InvalidName + { + return transformer.toName(name.toString()); + } + + /** + * Get the batch size from the environment properties. The batch size is used + * for listing operations. + * + * @return the batch size, or some default value if not specified. + */ + public int getBatchSize() + { + int batchSize = DEFAULT_BATCH_SIZE; + Object bs = properties.get(Context.BATCHSIZE); + if (bs != null) + { + try + { + int b = Integer.parseInt(bs.toString()); + if (b >= 0) + batchSize = b; + } + catch (NumberFormatException e) + { + // OK, use default value. + } + } + return batchSize; + } + + +} diff --git a/libjava/classpath/gnu/javax/naming/giop/CorbalocParser.java b/libjava/classpath/gnu/javax/naming/giop/CorbalocParser.java new file mode 100644 index 000000000..4b7883969 --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/giop/CorbalocParser.java @@ -0,0 +1,441 @@ +/* CorbalocParser.java -- handles corbaname: urls + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.naming.giop; + +import gnu.CORBA.IOR; +import gnu.CORBA.Minor; +import gnu.CORBA.Unexpected; +import gnu.CORBA.Version; +import gnu.CORBA.NamingService.NameTransformer; + +import gnu.java.lang.CPStringBuilder; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLDecoder; +import java.util.StringTokenizer; + +import javax.naming.InvalidNameException; + +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.DATA_CONVERSION; +import org.omg.CORBA.ORB; +import org.omg.CORBA.Object; +import org.omg.CORBA.ORBPackage.InvalidName; + +/** + * Parses the alternative IOR representations into our IOR structure. + * + * TODO This parser currently supports only one address per target string. A + * string with the multiple addresses will be accepted, but only the last + * address will be taken into consideration. The fault tolerance is not yet + * implemented. + * + * The key string is filtered using {@link java.net.URLDecoder} that replaces + * the agreed escape sequences by the corresponding non alphanumeric characters. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class CorbalocParser + extends NameTransformer +{ + /** + * The corbaloc prefix. + */ + public static final String pxCORBALOC = "corbaloc"; + + /** + * The corbaname prefix. + */ + public static final String pxCORBANAME = "corbaname"; + + /** + * The IOR prefix. + */ + public static final String pxIOR = "ior"; + + /** + * The file:// prefix. + */ + public static final String pxFILE = "file://"; + + /** + * The ftp:// prefix. + */ + public static final String pxFTP = "ftp://"; + + /** + * The http:// prefix. + */ + public static final String pxHTTP = "http://"; + + /** + * Marks iiop protocol. + */ + public static final String IIOP = "iiop"; + + /** + * Marks rir protocol. + */ + public static final String RIR = "rir"; + + /** + * The default port value, as specified in OMG documentation. + */ + public static final int DEFAULT_PORT = 2809; + + /** + * The default name. + */ + public static final String DEFAULT_NAME = "NameService"; + + /** + * The string to name converter, initialized on demand. + */ + static NameTransformer converter; + + /** + * The current position. + */ + int p; + + /** + * The address being parsed, splitted into tokens. + */ + String[] t; + + /** + * Parse CORBALOC. + * + * The expected format is:
+ * 1. corbaloc:[iiop][version.subversion@]:host[:port]/key
+ * 2. corbaloc:rir:[/key]
+ * 3. corbaname:[iiop][version.subversion@]:host[:port]/key
+ * 4. corbaname:rir:[/key]
+ * 5. file://[file name]
+ * 6. http://[url]
+ * 7. ftp://[url]
+ * + * Protocol defaults to IOP, the object key defaults to the NameService. + * + * @param corbaloc the string to parse. + * @param orb the ORB, needed to create IORs and resolve rir references. + * + * @return the arrey of strings, first member being the IOR of the + * naming service, second member the name in the naming service. + */ + public synchronized String[] corbaloc(String corbaloc, + ORB orb) + throws InvalidNameException + { + return corbaloc(corbaloc, orb, 0); + } + + /** + * Parse controlling against the infinite recursion loop. + */ + private String[] corbaloc(String corbaloc, + ORB orb, int recursion) throws InvalidNameException + { + // The used CORBA specification does not state how many times we should to + //redirect, but the infinite loop may be used to knock out the system. + // by malicious attempt. + if (recursion > 10) + throw new DATA_CONVERSION("More than 10 redirections"); + + if (corbaloc.startsWith(pxFILE)) + return corbaloc(readFile(corbaloc.substring(pxFILE.length())), orb, recursion+1); + else if (corbaloc.startsWith(pxHTTP)) + return corbaloc(readUrl(corbaloc), orb, recursion+1); + else if (corbaloc.startsWith(pxFTP)) + return corbaloc(readUrl(corbaloc), orb, recursion+1); + + // The version numbers with default values. + int major = 1; + int minor = 0; + + // The host address. + String host; + + // The port. + int port = DEFAULT_PORT; + + // The object key as string. + String key; + + StringTokenizer st = new StringTokenizer(corbaloc, ":@/.,#", true); + + t = new String[st.countTokens()]; + + for (int i = 0; i < t.length; i++) + { + t[i] = st.nextToken(); + } + + p = 0; + + if (!t[p].startsWith(pxCORBANAME)) + throw new InvalidNameException(corbaloc+" must start with "+pxCORBANAME); + + p++; + + if (!t[p++].equals(":")) + throw new BAD_PARAM("Syntax (':' expected after name prefix)"); + + // Check for rir: + if (t[p].equals(RIR)) + { + p++; + if (!t[p++].equals(":")) + throw new BAD_PARAM("':' expected after 'rir'"); + + key = readKey("/"); + + Object object; + try + { + object = orb.resolve_initial_references(key); + return resolve(orb.object_to_string(object)); + } + catch (InvalidName e) + { + throw new BAD_PARAM("Unknown initial reference '" + key + "'"); + } + } + else + // Check for iiop. + if (t[p].equals(IIOP) || t[p].equals(":")) + { + IOR ior = new IOR(); + + Addresses: do + { // Read addresses. + if (t[p].equals(":")) + { + p++; + } + else + { + p++; + if (!t[p++].equals(":")) + throw new BAD_PARAM("':' expected after 'iiop'"); + // Check if version is present. + if (t[p + 1].equals(".")) + if (t[p + 3].equals("@")) + { + // Version info present. + try + { + major = Integer.parseInt(t[p++]); + } + catch (NumberFormatException e) + { + throw new BAD_PARAM("Major version number '" + + t[p - 1] + "'"); + } + p++; // '.' at this point. + try + { + minor = Integer.parseInt(t[p++]); + } + catch (NumberFormatException e) + { + throw new BAD_PARAM("Major version number '" + + t[p - 1] + "'"); + } + p++; // '@' at this point. + } + } + + ior.Internet.version = new Version(major, minor); + + // Then host data goes till '/' or ':'. + CPStringBuilder bhost = new CPStringBuilder(corbaloc.length()); + while (!t[p].equals(":") && !t[p].equals("/") && !t[p].equals(",")) + bhost.append(t[p++]); + + host = bhost.toString(); + + ior.Internet.host = host; + + if (t[p].equals(":")) + { + // Port specified. + p++; + try + { + port = Integer.parseInt(t[p++]); + } + catch (NumberFormatException e) + { + throw new BAD_PARAM("Invalid port '" + t[p - 1] + "'"); + } + } + + ior.Internet.port = port; + + // Id is not listed. + ior.Id = ""; + + if (t[p].equals(",")) + p++; + else + break Addresses; + } + while (true); + + key = readKey("/"); + ior.key = key.getBytes(); + + return resolve(ior.toStringifiedReference()); + } + + else + throw new InvalidNameException("Unsupported protocol '" + t[p] + + "' (iiop expected)"); + } + + /** + * Read IOR from the file in the local file system. + */ + String readFile(String file) + { + File f = new File(file); + if (!f.exists()) + { + DATA_CONVERSION err = new DATA_CONVERSION(f.getAbsolutePath() + + " does not exist."); + err.minor = Minor.Missing_IOR; + } + try + { + char[] c = new char[(int) f.length()]; + FileReader fr = new FileReader(f); + fr.read(c); + fr.close(); + return new String(c).trim(); + } + catch (IOException ex) + { + DATA_CONVERSION d = new DATA_CONVERSION(); + d.initCause(ex); + d.minor = Minor.Missing_IOR; + throw (d); + } + } + + /** + * Read IOR from the remote URL. + */ + String readUrl(String url) + { + URL u; + try + { + u = new URL(url); + } + catch (MalformedURLException mex) + { + throw new BAD_PARAM("Malformed URL: '" + url + "'"); + } + + try + { + InputStreamReader r = new InputStreamReader(u.openStream()); + + CPStringBuilder b = new CPStringBuilder(); + int c; + + while ((c = r.read()) > 0) + b.append((char) c); + + return b.toString().trim(); + } + catch (Exception exc) + { + DATA_CONVERSION d = new DATA_CONVERSION("Reading " + url + " failed."); + d.minor = Minor.Missing_IOR; + throw d; + } + } + + private String[] resolve(String nsIor) + { + String [] n = new String[2]; + n[0] = nsIor; + n[1] = readKey("#"); + return n; + } + + private String readKey(String delimiter) + throws BAD_PARAM + { + if (p < t.length) + if (!t[p].equals(delimiter)) + { + if (t[p].equals("#")) + return DEFAULT_NAME; + else + throw new BAD_PARAM("'" + delimiter + "String' expected '" + t[p] + + "' found"); + } + + CPStringBuilder bKey = new CPStringBuilder(); + p++; + + while (p < t.length && !t[p].equals("#")) + bKey.append(t[p++]); + + if (bKey.length() == 0) + return DEFAULT_NAME; + + try + { + return URLDecoder.decode(bKey.toString(), "UTF-8"); + } + catch (UnsupportedEncodingException e) + { + throw new Unexpected("URLDecoder does not support UTF-8", e); + } + } +} diff --git a/libjava/classpath/gnu/javax/naming/giop/GiopNamingEnumeration.java b/libjava/classpath/gnu/javax/naming/giop/GiopNamingEnumeration.java new file mode 100644 index 000000000..c2de75b38 --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/giop/GiopNamingEnumeration.java @@ -0,0 +1,187 @@ +/* GiopNamingEnumeration.java -- handles corbaname: urls + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.naming.giop; + +import java.util.NoSuchElementException; + +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; + +import org.omg.CosNaming.Binding; +import org.omg.CosNaming.BindingIterator; +import org.omg.CosNaming.BindingIteratorHolder; +import org.omg.CosNaming.BindingListHolder; + +/** + * Iterates over name class pairs, obtaining values first from the binding list + * and then from the binding iterator. + * + * @author Audrius Meskauskas + */ +public abstract class GiopNamingEnumeration implements NamingEnumeration +{ + /** + * The array of bindings, returned at once. + */ + Binding[] list; + + /** + * The binding iterator to obtain the subsequent bindings. May be null, + * if all values are stored in the list. + */ + BindingIterator iterator; + + /** + * The batch size. + */ + int batch; + + /** + * The position of the element in the binding list, that must be returned + * during the subsequent call of the next(). If this field is grater or equal + * to the lenght of the list, the subsequent values must be requested from the + * iterator. + */ + int p; + + GiopNamingEnumeration(BindingListHolder bh, BindingIteratorHolder bih, int batchSize) + { + list = bh.value; + iterator = bih.value; + batch = batchSize; + } + + /** + * Convert from the CORBA binding into that this enumeration should return. + * + * @param binding + * the binding to convert + * @return the value, that must be returned by the {@link #next()}. + */ + public abstract Object convert(Binding binding); + + public void close() throws NamingException + { + if (iterator != null) + { + iterator.destroy(); + iterator = null; + } + } + + /** + * Checks if there are more elements to return. + * + * @throws NamingException + * never + */ + public boolean hasMore() throws NamingException + { + return hasMoreElements(); + } + + /** + * Returns the next element. + * + * @throws NamingException + * never + */ + public Object next() throws NamingException + { + return nextElement(); + } + + /** + * Checks if there are more elements to return. + */ + public boolean hasMoreElements() + { + if (p < 0) + return false; + else if (p < list.length) + return true; + else + return getMore(); + } + + /** + * Returns the next element. + */ + public Object nextElement() + { + if (p < 0) + throw new NoSuchElementException(); + else if (p < list.length) + return convert(list[p++]); + else if (getMore()) + // getMore updates p + return convert(list[p++]); + else + throw new NoSuchElementException(); + } + + /** + * Tries to obtain more elements, return true on success. Updates the fields + * accordingly. + */ + boolean getMore() + { + if (iterator != null) + { + BindingListHolder holder = new BindingListHolder(); + boolean rt = iterator.next_n(batch, holder); + if (rt) + { + // The new pack of the bindings arrived. + p = 0; + list = holder.value; + return true; + } + else + { + iterator.destroy(); + iterator = null; + p = -1; + return false; + } + } + else + return false; + } +} diff --git a/libjava/classpath/gnu/javax/naming/giop/GiopNamingServiceFactory.java b/libjava/classpath/gnu/javax/naming/giop/GiopNamingServiceFactory.java new file mode 100644 index 000000000..e8aac3b65 --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/giop/GiopNamingServiceFactory.java @@ -0,0 +1,179 @@ +/* GiopNamingServiceFactory.java -- handles corbaname: urls + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.naming.giop; + +import gnu.CORBA.OrbFunctional; + +import gnu.java.lang.CPStringBuilder; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; +import java.util.TreeMap; + +import javax.naming.Context; +import javax.naming.Name; + +import org.omg.CORBA.ORB; + +/** + * The context factory to represent the corbaname: style urls. Such URL states + * that the CORBA naming service exists on the given host. This service can + * return the required object, finding it by the given name. The names are + * parsed using the specification of the corbaname urls. Being the naming + * service, the returned context supports creating the subcontexts, forwarding + * this task to the existing naming service. + * + * @author Audrius Meskauskas (audriusa@Bioinformatics.org) + */ +public class GiopNamingServiceFactory +{ + /** + * The default naming service provider. It is assumed, that the naming service + * is running on the port 900 of the local host, using the GIOP version 1.2 + */ + public static final String DEFAULT_PROVIDER = + "corbaloc:iiop:1.2@127.0.0.1:900/NameService"; + + /** + * The table of all instantiated ORB's that are found by they ORB + * properties signatures. If all ORB related properties are the same, + * the ORB's are shared. + */ + public static Hashtable orbs = new Hashtable(); + + + /** + * Create a new instance of the corbaname URL context. + */ + public Object getObjectInstance(Object refObj, Name name, Context nameCtx, + Hashtable environment) + { + String provider = (String) environment.get(Context.PROVIDER_URL); + if (provider == null) + provider = DEFAULT_PROVIDER; + + String orbSignature = getOrbSignature(environment); + + ORB orb; + synchronized (orbs) + { + orb = (ORB) orbs.get(orbSignature); + if (orb == null) + { + Properties props = new Properties(); + props.putAll(environment); + orb = ORB.init(new String[0], props); + orbs.put(orbSignature, orb); + final ORB runIt = orb; + new Thread() + { + public void run() + { + runIt.run(); + } + }.start(); + } + } + + return new GiopNamingServiceURLContext(environment, this, orb); + } + + /** + * Check if this ORB is still in use (maybe it is time to shutdown it). This + * method only works when the Classpath CORBA implementation is used + * (otherwise it return without action). The method is called from the close() + * method of the created context. + * + * @param orb + * the ORB that maybe is no longer referenced. + */ + public void checkIfReferenced(ORB orb) + { + synchronized (orbs) + { + // We can only do this with the Classpath implementation. + if (orb instanceof OrbFunctional) + { + OrbFunctional cOrb = (OrbFunctional) orb; + // If there are no connected objects, we can destroy the orb. + if (cOrb.countConnectedObjects() == 0) + { + cOrb.shutdown(false); + cOrb.destroy(); + + Enumeration keys = orbs.keys(); + Object key; + Remove: while (keys.hasMoreElements()) + { + key = keys.nextElement(); + if (orbs.get(key) == orb) + { + orbs.remove(key); + break Remove; + } + } + } + } + } + } + + /** + * Get all properties. + */ + public String getOrbSignature(Map props) + { + TreeMap map = new TreeMap(); + map.putAll(props); + CPStringBuilder b = new CPStringBuilder(50*props.size()); + + Iterator iter = map.entrySet().iterator(); + Map.Entry m; + while (iter.hasNext()) + { + m = (Map.Entry) iter.next(); + b.append(m.getKey()); + b.append('='); + b.append(m.getValue()); + } + return b.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/naming/giop/GiopNamingServiceURLContext.java b/libjava/classpath/gnu/javax/naming/giop/GiopNamingServiceURLContext.java new file mode 100644 index 000000000..0d2e290b4 --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/giop/GiopNamingServiceURLContext.java @@ -0,0 +1,840 @@ +/* GiopNamingServiceURLContext.java -- handles corbaname: urls + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.naming.giop; + +import gnu.CORBA.NamingService.Ext; +import gnu.CORBA.NamingService.NameTransformer; + +import java.util.Hashtable; + +import javax.naming.Binding; +import javax.naming.Context; +import javax.naming.ContextNotEmptyException; +import javax.naming.InvalidNameException; +import javax.naming.Name; +import javax.naming.NameAlreadyBoundException; +import javax.naming.NameClassPair; +import javax.naming.NameNotFoundException; +import javax.naming.NameParser; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.OperationNotSupportedException; +import javax.naming.directory.InvalidAttributesException; + +import org.omg.CORBA.ORB; +import org.omg.CORBA.portable.Delegate; +import org.omg.CORBA.portable.ObjectImpl; +import org.omg.CosNaming.BindingIteratorHolder; +import org.omg.CosNaming.BindingListHolder; +import org.omg.CosNaming.NameComponent; +import org.omg.CosNaming.NamingContext; +import org.omg.CosNaming.NamingContextExt; +import org.omg.CosNaming.NamingContextExtHelper; +import org.omg.CosNaming.NamingContextHelper; +import org.omg.CosNaming._NamingContextExtStub; +import org.omg.CosNaming._NamingContextStub; +import org.omg.CosNaming.NamingContextPackage.AlreadyBound; +import org.omg.CosNaming.NamingContextPackage.CannotProceed; +import org.omg.CosNaming.NamingContextPackage.InvalidName; +import org.omg.CosNaming.NamingContextPackage.NotFound; + +/** + * The context to represent the corba naming service. Being the naming service, + * the returned context supports creating the subcontexts, forwarding this task + * to the existing naming service. When listing bindings, it uses the + * {@link Context#BATCHSIZE} property to determine, how many bindings should + * be returned at once (the process is transparend) + * + * @author Audrius Meskauskas (audriusa@Bioinformatics.org) + */ +public class GiopNamingServiceURLContext extends CorbalocParser implements + Context +{ + /** + * This number of bindings will be requested from the naming server at once, + * while the subsequent bindings will be requested via binding iterator one by + * one. Use {@link Context#BATCHSIZE} to override the value of this constant. + */ + public int DEFAULT_BATCH_SIZE = 20; + + /** + * The object request broker, used to access the naming service. This field + * is only initialised when the context is constructed from the URL. + */ + ORB orb; + + /** + * The properties. + */ + Hashtable properties; + + /** + * The parent factory. + */ + GiopNamingServiceFactory factory; + + /** + * The name transformer to obtain the name from its string representation. The + * to_name method of the naming service is avoided as it may be remote and + * hence expensive. The conversion rules are standard and cannot be service + * specific. + */ + static NameTransformer transformer = new NameTransformer(); + + /** + * The batch size for list operations - how many to return at once. + */ + public final int howMany; + + /** + * Creates a new naming context that uses naming service, represented by the + * given CORBA object. + * + * @param props + * the environment table. + * @param aFactory + * parent factory. This reference is used during cleanup. + * @param anOrb + * the associated ORB. This reference is used during cleanup. + */ + public GiopNamingServiceURLContext(Hashtable props, + GiopNamingServiceFactory aFactory, + ORB anOrb) + { + factory = aFactory; + orb = anOrb; + + properties = props; + howMany = getBatchSize(); + } + + public NamingContextExt getService(String address) + { + org.omg.CORBA.Object nsObject = orb.string_to_object(address); + Delegate delegate = ((ObjectImpl) nsObject)._get_delegate(); + + // If the IOR provides the IDL ID, we can check if our name + // service is old NamingContext or new NamingContextExt. + // Not all forms of the URL always provide the IDL id. + if (!nsObject._is_a(NamingContextExtHelper.id()) + && nsObject._is_a(NamingContextHelper.id())) + { + // We are surely working with the old version. + _NamingContextStub stub = new _NamingContextStub(); + stub._set_delegate(delegate); + // The Ext object will add the necessary extensions. + return new Ext(stub); + } + else + { + // We expecte the service to be the NamingContextExt (this is true + // for both Sun's and our implementations). There is no easy way + // to check the version. + _NamingContextExtStub stub = new _NamingContextExtStub(); + stub._set_delegate(delegate); + return stub; + } + } + + /** + * Split the corbaname name into the address of the naming service (first + * part) and the name of the object in the naming service (second part) + */ + public String[] split(String corbaloc) throws InvalidNameException + { + if (corbaloc.endsWith("#")) + corbaloc = corbaloc.substring(0, corbaloc.length() - 1); + + // No name part - parse as corbaname. + if (corbaloc.indexOf('#') < 0) + { + if (!corbaloc.regionMatches(true, 0, pxCORBANAME, 0, + pxCORBANAME.length())) + throw new InvalidNameException(corbaloc + " must start with " + + pxCORBANAME); + corbaloc = pxCORBALOC + corbaloc.substring(pxCORBANAME.length()); + return new String[] { corbaloc, "" }; + } + + return corbaloc(corbaloc, orb); + } + + /** + * Give the specified name for the specified object. The passed name must not + * be already bound to some other object. The components of the name are + * mapped into the components of the CORBA name. + * + * @param name + * the name that will be given to the object (in the scope of this + * context). + * @param obj + * the object being named. + * @throws NameAlreadyBoundException + * if this name is already used to name some object. + * @throws InvalidAttributesException + * if the object does not supply all required attributes. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void bind(Name name, Object obj) throws NamingException + { + bind(name.toString(), obj); + } + + /** + * Give the specified name for the specified object. The passed name must not + * be already bound to some other object. + * + * @param name + * the name that will be given to the object (in the scope of this + * context). + * @param obj + * the object being named. + * @throws NameAlreadyBoundException + * if this name is already used to name some object. + * @throws InvalidAttributesException + * if the object does not supply all required attributes. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void bind(String name, Object obj) throws NamingException + { + try + { + String[] n = split(name); + org.omg.CORBA.Object object = (org.omg.CORBA.Object) obj; + getService(n[0]).bind(transformer.toName(n[1]), object); + } + catch (ClassCastException e) + { + throw new NamingException(org.omg.CORBA.Object.class + " required "); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + catch (AlreadyBound e) + { + throw new NameAlreadyBoundException(); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Releases all resources, associated with this context. The close() method + * can be called several times, but after it has been once invoked, it is not + * allowed to call any other method of this context. This method destroys + * the ORB, if we have one. + * + * @throws NamingException + */ + public void close() throws NamingException + { + if (orb != null && factory != null) + { + factory.checkIfReferenced(orb); + } + } + + /** + * Not supported. + */ + public Name composeName(Name name, Name prefix) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported + */ + public String composeName(String name1, String name2) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Creates the new naming subcontext and binds it to the current (this) + * context. The returned object will wrap around the newly created CORBA + * subcontext + * + * @param subContext + * the name of the new context being created + * @return the newly created context, bound to the instance of the context on + * that the method has been called + * @throws NameAlreadyBoundException + * if this name is already bound + * @throws InvalidAttributesException + * if the creation of the new context requires the missing mandatory + * attributes + * @throws NamingException + */ + public Context createSubcontext(Name subContext) throws NamingException + { + return createSubcontext(subContext.toString()); + } + + /** + * Creates the new naming subcontext and binds it to the current (this) + * context. The returned object will wrap around the newly created CORBA + * subcontext + * + * @param subContext + * the name of the new context being created + * @return the newly created context, bound to the instance of the context on + * that the method has been called + * @throws NameAlreadyBoundException + * if this name is already bound + * @throws InvalidAttributesException + * if the creation of the new context requires the missing mandatory + * attributes + * @throws NamingException + */ + public Context createSubcontext(String subContext) throws NamingException + { + try + { + String[] n = split(subContext); + org.omg.CORBA.Object subcontext = getService(n[0]).bind_new_context( + transformer.toName(n[1])); + Hashtable clonedProps = new Hashtable(); + clonedProps.putAll(properties); + + // Nulls are passed both for orb and factory, as the child contexts + // need not to do any cleanup. + return new ContextContinuation(subcontext, clonedProps, null, null); + } + catch (AlreadyBound e) + { + throw new NameAlreadyBoundException(subContext); + } + catch (InvalidName e) + { + throw new InvalidNameException(subContext); + } + catch (Exception ex) + { + throw new NamingException(ex.toString()); + } + } + + /** + * Removes the naming subcontext from this naming context. Returns without + * action if such subcontext does not exist. The context being destroyed must + * be empty. + * + * @param subContext + * the name of the subcontext beig removed. + * @throws ContextNotEmptyException + * if the named context is not empty. + * @throws NamingException + */ + public void destroySubcontext(Name subContext) throws NamingException + { + unbind(subContext); + } + + /** + * Removes the naming subcontext from this naming context. Returns without + * action if such subcontext does not exist. The context being destroyed must + * be empty. + * + * @param subContext + * the name of the subcontext beig removed. + * @throws ContextNotEmptyException + * if the named context is not empty. + * @throws NamingException + */ + public void destroySubcontext(String subContext) throws NamingException + { + unbind(subContext); + } + + /** + * Returs the empty string. + */ + public String getNameInNamespace() throws NamingException + { + return ""; + } + + /** + * Not supported. + */ + public NameParser getNameParser(Name name) throws NamingException + { + throw new UnsupportedOperationException(); + } + + /** + * Not supported. + */ + public NameParser getNameParser(String name) throws NamingException + { + throw new UnsupportedOperationException(); + } + + /** + * Creates and returns the enumeration over the name bindings that are present + * the given subcontext. The enumeration elements have the type of + * {@link NameClassPair}, providing also information about the class of the + * bound object. The behaviour in the case if the bindings are added or + * removed later is not defined. The contents of the subcontexts are not + * included. + * + * @param name + * the name of the subcontext + * @return the enumeration over the names, known for the given subcontext. + * @throws NamingException + */ + public NamingEnumeration list(Name name) throws NamingException + { + return list(name.toString()); + } + + /** + * Creates and returns the enumeration over the name bindings that are present + * the given subcontext. The enumeration elements have the type of + * {@link NameClassPair}, providing also information about the class of the + * bound object. The behaviour in the case if the bindings are added or + * removed later is not defined. The contents of the subcontexts are not + * included. + * + * @param name + * the name of the subcontext + * @return the enumeration over the names, known for the given subcontext. + * @throws NamingException + */ + public NamingEnumeration list(String name) throws NamingException + { + BindingIteratorHolder bi = new BindingIteratorHolder(); + BindingListHolder bl = new BindingListHolder(); + + NamingContext subcontext; + + String [] n = split(name); + NamingContextExt service = getService(n[0]); + + if (n[1].length() == 0) + subcontext = service; + else + { + try + { + subcontext = (NamingContextHelper.narrow(service.resolve_str(n[1]))); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + + } + + subcontext.list(howMany, bl, bi); + + return new ListEnumeration(bl, bi, howMany); + } + + /** + * Creates and returns the enumeration over the name - object bindings that + * are present the given subcontext. The enumeration elements have the type of + * {@link Binding}, providing also information about the class of the bound + * object. The behaviour in the case if the bindings are added or removed + * later is not defined. The contents of the subcontexts are not included. + * + * @param name + * the name of the subcontext + * @return the enumeration over the names, known for the given subcontext. + * @throws NamingException + */ + public NamingEnumeration listBindings(Name name) throws NamingException + { + return listBindings(name.toString()); + } + + /** + * Creates and returns the enumeration over the name - object bindings that + * are present the given subcontext. The enumeration elements have the type of + * {@link Binding}, providing also information about the class of the bound + * object. The behaviour in the case if the bindings are added or removed + * later is not defined. The contents of the subcontexts are not included. + * + * @param name + * the name of the subcontext + * @return the enumeration over the names, known for the given subcontext. + * @throws NamingException + */ + public NamingEnumeration listBindings(String name) throws NamingException + { + BindingIteratorHolder bi = new BindingIteratorHolder(); + BindingListHolder bl = new BindingListHolder(); + + NamingContext subcontext; + + String [] n = split(name); + NamingContextExt service = getService(n[0]); + + if (n[1].length() == 0) + subcontext = service; + else + { + try + { + subcontext = (NamingContextHelper.narrow(service.resolve_str(n[1]))); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + + } + + subcontext.list(howMany, bl, bi); + + return new ListBindingsEnumeration(bl, bi, howMany, subcontext); + } + + /** + * Gets the previously named object by name. If the passed name is empty, the + * method should return a cloned instance of this naming context. + * + * @param name + * the name of the object being searched in this context + * @return the named object + * @throws NameNotFoundException + * if the name is not found + */ + public Object lookup(Name name) throws NamingException + { + return lookup(name.toString()); + } + + /** + * Gets the previously named object by name. If the passed name is empty, the + * method should return a cloned instance of this naming context. + * + * @param name + * the name of the object being searched in this context + * @return the named object + * @throws NamingException + * if the naming fails. + */ + public Object lookup(String name) throws NamingException + { + try + { + String [] n = split(name); + NamingContextExt service = getService(n[0]); + return service.resolve_str(n[1]); + } + catch (NotFound e) + { + throw new NameNotFoundException(); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Not supported. + */ + public Object lookupLink(Name name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported. + */ + public Object lookupLink(String name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Give the specified name for the specified object. Unlike bind, this method + * silently replaces the existing binding for this name, if one exists. + * + * @param name + * the name that will be given to the object (in the scope of this + * context). + * @param obj + * the object being named. + * @throws InvalidAttributesException + * if the object does not supply all required attributes. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void rebind(Name name, Object obj) throws NamingException + { + rebind(name.toString(), obj); + } + + /** + * Give the specified name for the specified object. Unlike bind, this method + * silently replaces the existing binding for this name, if one exists. + * + * @param name + * the name that will be given to the object (in the scope of this + * context). + * @param obj + * the object being named. + * @throws InvalidAttributesException + * if the object does not supply all required attributes. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void rebind(String name, Object obj) throws NamingException + { + try + { + String[] n = split(name); + NamingContextExt service = getService(n[0]); + + org.omg.CORBA.Object object = (org.omg.CORBA.Object) obj; + service.rebind(transformer.toName(n[1]), object); + } + catch (ClassCastException e) + { + throw new NamingException(org.omg.CORBA.Object.class + " required "); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Renames the existing binding, removing the existing and giving the new name + * for the same object. + * + * @param oldName + * the existing name of the known object + * @param newName + * the new name of the same object + * @throws NameNotFoundException + * if the oldName is unknown for this context + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void rename(Name oldName, Name newName) throws NamingException + { + Object object = lookup(oldName); + unbind(oldName); + bind(newName, object); + } + + /** + * Renames the existing binding, removing the existing and giving the new name + * for the same object. + * + * @param oldName + * the existing name of the known object + * @param newName + * the new name of the same object + * @throws NameNotFoundException + * if the oldName is unknown for this context + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void rename(String oldName, String newName) throws NamingException + { + Object object = lookup(oldName); + unbind(oldName); + bind(newName, object); + } + + /** + * Removes the name - object mapping from the current context. This method + * returns without action if the name is not bound to an object in the + * terminal context, but throws {@link NameNotFoundException} if one of the + * intermadiate contexts does not exist. + * + * @param name + * the name to be removed + * @throws NameNotFoundException + * if one of the intermediate naming contexts does not exist. Will + * not be thrown if just the terminal binding is missing. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void unbind(Name name) throws NamingException + { + unbind(name.toString()); + } + + /** + * Removes the name - object mapping from the current context. This method + * returns without action if the name is not bound to an object in the + * terminal context, but throws {@link NameNotFoundException} if one of the + * intermadiate contexts does not exist. + * + * @param name + * the name to be removed + * @throws NameNotFoundException + * if one of the intermediate naming contexts does not exist. Will + * not be thrown if just the terminal binding is missing. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void unbind(String name) throws NamingException + { + try + { + String[] n = split(name); + NamingContextExt service = getService(n[0]); + + service.unbind(transformer.toName(n[1])); + } + catch (NotFound e) + { + throw new NameNotFoundException(name); + } + catch (CannotProceed e) + { + throw new ContextNotEmptyException(name); + } + catch (InvalidName e) + { + throw new InvalidNameException(name); + } + } + + /** + * Add new environment property to the environment of this context. Both name + * and value of the new property must not be null. If the property is already + * defined, is current value is replaced by the propVal. + * + * @param key + * the name of the new property + * @param value + * the value of the new property + * @return the previous value of this property or null if the property has not + * been previously defined + * @throws NamingException + */ + public Object addToEnvironment(String key, Object value) + throws NamingException + { + if (key == null || value == null) + throw new NullPointerException(); + return properties.put(key, value); + } + + /** + * Returns the environment, associated with this naming context. The returned + * table should never be modified by the caller. Use {@link #addToEnvironment} + * and {@link #removeFromEnvironment} to modify the environement, if needed. + * + * @return the table, representing the environment of this context + * @throws NamingException + */ + public Hashtable getEnvironment() throws NamingException + { + return properties; + } + + /** + * Removes the property with the given name from the environment. Returns + * without action if this property is not defined. + * + * @param propName + * the name of the property being removed. + * @return the value of the property that has been removed or null if the + * property was not defined. + * @throws NamingException + */ + public Object removeFromEnvironment(String propName) throws NamingException + { + return properties.remove(propName); + } + + /** + * Convert the {@link Name} into array of the name components, required to the + * CORBA naming service. First the string representation is obtained, then + * it is converted using parsing rules of the CORBA name. + * + * @param name + * then name to convert + * @return the converted array of components. + */ + public NameComponent[] toGiop(Name name) throws InvalidName + { + return transformer.toName(name.toString()); + } + + /** + * Get the batch size from the environment properties. The batch size is used + * for listing operations. + * + * @return the batch size, or some default value if not specified. + */ + public int getBatchSize() + { + int batchSize = DEFAULT_BATCH_SIZE; + Object bs = properties.get(Context.BATCHSIZE); + if (bs != null) + { + try + { + int b = Integer.parseInt(bs.toString()); + if (b >= 0) + batchSize = b; + } + catch (NumberFormatException e) + { + // OK, use default value. + } + } + return batchSize; + } + +} diff --git a/libjava/classpath/gnu/javax/naming/giop/ListBindingsEnumeration.java b/libjava/classpath/gnu/javax/naming/giop/ListBindingsEnumeration.java new file mode 100644 index 000000000..dd9ed0265 --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/giop/ListBindingsEnumeration.java @@ -0,0 +1,118 @@ +/* ListBindingsEnumeration.java -- handles corbaname: urls + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.naming.giop; + +import gnu.java.lang.CPStringBuilder; + +import javax.naming.NamingEnumeration; + +import org.omg.CosNaming.Binding; +import org.omg.CosNaming.BindingIteratorHolder; +import org.omg.CosNaming.BindingListHolder; +import org.omg.CosNaming.NamingContext; + +/** + * Iterates over bindings, obtaining values first from the binding list and then + * from the binding iterator. + * + * @author Audrius Meskauskas + */ +public class ListBindingsEnumeration extends GiopNamingEnumeration implements + NamingEnumeration +{ + /** + * The naming service, to resolve the objects. + */ + NamingContext service; + + /** + * Create the new enumeration + * + * @param bh + * holder, containing the first portion of the bindings + * @param bih + * the iterator, containing the remaining bindings + * @param batchSize + * the number of bindings the the iterator will be requested to + * return as a single pack + * @param aService + * the naming service, used to obtain the objects, bound to the + * names. + */ + public ListBindingsEnumeration(BindingListHolder bh, + BindingIteratorHolder bih, int batchSize, + NamingContext aService) + { + super(bh, bih, batchSize); + service = aService; + } + + /** + * Convert from the CORBA binding into the javax.naming binding. As the CORBA + * naming service binding does not contain the object itself, this method + * makes the additional calls to the naming service. + * + * @param binding + * the binding to convert + * @return the value, that must be returned by the {@link #next()}. + */ + public Object convert(Binding binding) + { + CPStringBuilder name = new CPStringBuilder(); + + for (int i = 0; i < binding.binding_name.length; i++) + { + name.append(binding.binding_name[i]); + if (i < binding.binding_name.length - 1) + name.append('/'); + } + + try + { + Object object = service.resolve(binding.binding_name); + return new javax.naming.Binding(name.toString(), object); + } + catch (Exception e) + { + // Probably was removed by the concurent thread. + return null; + } + } + +} diff --git a/libjava/classpath/gnu/javax/naming/giop/ListEnumeration.java b/libjava/classpath/gnu/javax/naming/giop/ListEnumeration.java new file mode 100644 index 000000000..68a40fcf0 --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/giop/ListEnumeration.java @@ -0,0 +1,118 @@ +/* ListEnumeration.java -- handles corbaname: urls + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +odule. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.naming.giop; + +import gnu.java.lang.CPStringBuilder; + +import javax.naming.NameClassPair; +import javax.naming.NamingEnumeration; + +import org.omg.CosNaming.Binding; +import org.omg.CosNaming.BindingIteratorHolder; +import org.omg.CosNaming.BindingListHolder; +import org.omg.CosNaming.BindingType; +import org.omg.CosNaming.NamingContext; + +/** + * Iterates over name class pairs, obtaining values first from the binding list + * and then from the binding iterator. + * + * @author Audrius Meskauskas + */ +public class ListEnumeration extends GiopNamingEnumeration implements + NamingEnumeration +{ + /** + * Create the new enumeration + * + * @param bh + * holder, containing the first portion of the bindings + * @param bih + * the iterator, containing the remaining bindings + * @param batchSize + * the number of bindings the the iterator will be requested to + * return as a single pack + */ + public ListEnumeration(BindingListHolder bh, + BindingIteratorHolder bih, int batchSize) + { + super(bh, bih, batchSize); + } + + /** + * Convert from the CORBA binding into the {@link NameClassPair} that this + * enumeration should return. This method converts into NameClassPair, + * connecting the name components with slashes and setting the class name + * to either NamingContext or GIOP Object. + * + * @param binding + * the binding to convert + * @return the value, that must be returned by the {@link #next()}. + */ + public Object convert(Binding binding) + { + CPStringBuilder name = new CPStringBuilder(); + + for (int i = 0; i < binding.binding_name.length; i++) + { + name.append(binding.binding_name[i]); + if (i < binding.binding_name.length - 1) + name.append('/'); + } + + String className; + + switch (binding.binding_type.value()) + { + case BindingType._ncontext: + className = NamingContext.class.getName(); + break; + case BindingType._nobject: + className = org.omg.CORBA.Object.class.getName(); + break; + default: + className = Object.class.getName(); + break; + } + + NameClassPair pair = new NameClassPair(name.toString(), className); + return pair; + } + +} diff --git a/libjava/classpath/gnu/javax/naming/ictxImpl/trans/GnuName.java b/libjava/classpath/gnu/javax/naming/ictxImpl/trans/GnuName.java new file mode 100644 index 000000000..f37f8022d --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/ictxImpl/trans/GnuName.java @@ -0,0 +1,469 @@ +/* GnuName.java -- implementation of the javax.naming.Name + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.naming.ictxImpl.trans; + +import gnu.java.lang.CPStringBuilder; + +import java.util.Enumeration; +import java.util.NoSuchElementException; + +import javax.naming.InvalidNameException; +import javax.naming.Name; + +/** + * The implementation of the {@link Name}. + * + * @author Audrius Meskauskas + */ +public class GnuName + implements Name +{ + /** + * The enumeration to traverse over name components. + */ + class GnuNameEnum + implements Enumeration + { + /** + * Get the new enumeration that enumerates from the given position forward + * + * @param position the position of the first name component to enumerate (0 + * means first element) + */ + GnuNameEnum(int position) + { + nxt = from + position; + } + + /** + * The position of the next enumeration component to be returned or -1 if + * the end has been reached. + */ + int nxt; + + /** + * Check if there are more elements in this enumeration. + */ + public boolean hasMoreElements() + { + return nxt >= 0; + } + + /** + * Return the next element or throw a NoSuchElementException if there is no + * any. + */ + public Object nextElement() + { + if (nxt < 0) + throw new NoSuchElementException(); + Object r = content[nxt++]; + + if (nxt - from == length) + nxt = - 1; + + return r; + } + } + + private static final long serialVersionUID = - 3617482732056931635L; + + /** + * The hashcode + */ + int hash; + + /** + * The content buffer of the name. This buffer may be shared, so the array + * member content should never be modified. + */ + String[] content; + + /** + * The place, inclusive, where the name content starts in the content buffer. + */ + int from; + + /** + * The length of the name. + */ + int length; + + /** + * Creates the unitialised name. + */ + protected GnuName() + { + + } + + /** + * Creates the name, containing from the given chain of the atomic components. + * + * @param name the array, containing the name components. + */ + public GnuName(String[] name) + { + this(name, 0, name.length); + } + + /** + * Creates the name that uses the given portion of the array for its + * components. + */ + public GnuName(String[] buffer, int useFrom, int useLength) + { + content = buffer; + from = useFrom; + length = useLength; + } + + /** + * Inserts the given String component to this Name + * at the given index. The method modifies the current Name and + * then returns it. + * + * @exception ArrayIndexOutOfBoundsException if the given index is smaller + * then zero or greater then or equal to size(). + * @exception InvalidNameException if the given String is not a + * valid component for this Name. + */ + public Name add(int posn, String comp) throws InvalidNameException + { + String[] nc = new String[content.length + 1]; + System.arraycopy(content, from, nc, 0, posn); + nc[posn] = comp; + System.arraycopy(content, from + posn, nc, posn + 1, length - posn); + + content = nc; + from = 0; + length = content.length; + hash = 0; + return this; + } + + /** + * Adds the given String component to the end of this + * Name. The method modifies the current Name + * and then returns it. + * + * @exception InvalidNameException if the given String is not a + * valid component for this Name. + */ + public Name add(String comp) throws InvalidNameException + { + String[] nc = new String[content.length + 1]; + System.arraycopy(content, from, nc, 0, length); + nc[nc.length - 1] = comp; + + content = nc; + from = 0; + length = content.length; + hash = 0; + return this; + } + + /** + * Inserts all the components of the given Name to this + * Name at the given index. Components after this index (if + * any) are shifted up. The method modifies the current Name + * and then returns it. + * + * @exception ArrayIndexOutOfBoundsException if the given index is smaller + * then zero or greater then or equal to size(). + * @exception InvalidNameException if any of the given components is not a + * valid component for this Name. + */ + public Name addAll(int posn, Name n) throws InvalidNameException + { + String[] nc = new String[length + n.size()]; + System.arraycopy(content, from, nc, 0, posn); + + int i = posn; + for (int p = 0; p < n.size(); i++, p++) + nc[i] = n.get(p); + + System.arraycopy(content, from + posn, nc, i, length - posn); + + length = length + n.size(); + hash = 0; + content = nc; + return this; + } + + /** + * Adds all the components of the given Name to the end of this + * Name. The method modifies the current Name + * and then returns it. + * + * @exception InvalidNameException if any of the given components is not a + * valid component for this Name. + */ + public Name addAll(Name suffix) throws InvalidNameException + { + String[] nc = new String[length + suffix.size()]; + System.arraycopy(content, from, nc, 0, length); + + for (int i = length, p = 0; i < nc.length; i++, p++) + nc[i] = suffix.get(p); + + length = length + suffix.size(); + hash = 0; + content = nc; + return this; + } + + /** + * Compares the given object to this Name. Returns a negative + * value if the given Object is smaller then this + * Name, a positive value if the Object is + * bigger, and zero if the are equal. If the Object is not of a + * class that can be compared to the class of this Name then a + * ClassCastException is thrown. Note that it is not guaranteed + * that Names implemented in different classes can be + * compared. The definition of smaller, bigger and equal is up to the actual + * implementing class. + */ + public int compareTo(Object obj) + { + Name n = (Name) obj; + + int l = Math.min(length, n.size()); + int c; + + for (int i = 0; i < l; i++) + { + c = content[from + i].compareTo(n.get(i)); + if (c != 0) + return c; + } + return length - n.size(); + } + + /** + * Returns true if this Name ends with the + * components of the given Name, false + * otherwise. + */ + public boolean endsWith(Name n) + { + if (n.size() > length) + return false; + + int ofs = length - n.size() + from; + + for (int i = 0; i < n.size(); i++, ofs++) + if (! content[ofs].equals(n.get(i))) + return false; + + return true; + } + + /** + * Gets the component at the given index. + * + * @exception ArrayIndexOutOfBoundsException if the given index is smaller + * then zero or greater then or equal to size(). + */ + public String get(int posn) + { + return content[from + posn]; + } + + /** + * Returns a non-null (but possibly empty) Enumeration of the + * components of the Name as Strings. + */ + public Enumeration getAll() + { + return new GnuNameEnum(0); + } + + /** + * Returns the components till the given index as a Name. The + * returned Name can be modified without changing the original. + * + * @param posn the ending position, exclusive + * @exception ArrayIndexOutOfBoundsException if the given index is smaller + * then zero or greater then or equal to size(). + */ + public Name getPrefix(int posn) + { + return new GnuName(content, from, posn); + } + + /** + * Returns the components from the given index till the end as a + * Name. The returned Name can be modified + * without changing the original. + * + * @param posn the starting position, inclusive. If it is equal to the size of + * the name, the empty name is returned. + * @exception ArrayIndexOutOfBoundsException if the given index is smaller + * then zero or greater then or equal to size(). + */ + public Name getSuffix(int posn) + { + return new GnuName(content, from + posn, length - posn); + } + + /** + * Returns true if the number of components of this + * Name is zero, false otherwise. + */ + public boolean isEmpty() + { + return length == 0; + } + + /** + * Removes the component at the given index from this Name. + * The method modifies the current Name and then returns it. + * + * @exception InvalidNameException if the name size reduces below zero. + */ + public Object remove(int posn) throws InvalidNameException + { + if (length == 0) + throw new InvalidNameException("negative size"); + else + { + length--; + if (posn == 0) + from++; + else if (posn < length) + { + String[] nc = new String[length]; + System.arraycopy(content, from, nc, 0, posn); + System.arraycopy(content, from + posn + 1, nc, posn, length - posn); + content = nc; + from = 0; + } + } + hash = 0; + return this; + } + + /** + * Returns the number of components of this Name. The returned + * number can be zero. + */ + public int size() + { + return length; + } + + /** + * Returns true if this Name starts with the + * components of the given Name, false + * otherwise. + */ + public boolean startsWith(Name n) + { + if (n.size() > length) + return false; + + for (int i = 0; i < n.size(); i++) + if (! content[from + i].equals(n.get(i))) + return false; + + return true; + } + + /** + * Returns a clone of this Name. It will be a deep copy of all + * the components of the Name so that changes to components of + * the components does not change the component in this Name. + */ + public Object clone() + { + return new GnuName(content, from, length); + } + + /** + * The name is equal to other name if they contents are equal. + */ + public boolean equals(Object arg0) + { + if (this == arg0) + return true; + else if (arg0 instanceof Name) + { + Name n = (Name) arg0; + if (length != n.size()) + return false; + + for (int i = 0; i < length; i++) + if (! content[from + i].equals(n.get(i))) + return false; + return true; + } + else + return false; + } + + /** + * Overridden to make consistent with equals. + */ + public int hashCode() + { + if (hash == 0 && length > 0) + { + int s = 0; + for (int i = from; i < from + length; i++) + s ^= content[i].hashCode(); + hash = s; + } + return hash; + } + + /** + * Get the string representation, separating the name components by slashes + */ + public String toString() + { + CPStringBuilder b = new CPStringBuilder(); + for (int i = 0; i < length; i++) + { + b.append(get(i)); + if (i < length - 1) + b.append('/'); + } + return b.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/naming/jndi/url/corbaname/corbanameURLContextFactory.java b/libjava/classpath/gnu/javax/naming/jndi/url/corbaname/corbanameURLContextFactory.java new file mode 100644 index 000000000..c6fb8481f --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/jndi/url/corbaname/corbanameURLContextFactory.java @@ -0,0 +1,53 @@ +/* corbanameURLContextFactory.java -- handles corbaname: urls + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.naming.jndi.url.corbaname; + +import gnu.javax.naming.giop.GiopNamingServiceFactory; + +import javax.naming.spi.ObjectFactory; + +/** + * The GIOP URL context factory. + * + * @author Audrius Meskauskas (audriusa@Bioinformatics.org) + */ +public class corbanameURLContextFactory extends GiopNamingServiceFactory + implements ObjectFactory +{ + // Nothing to override here. +} diff --git a/libjava/classpath/gnu/javax/naming/jndi/url/rmi/ContextContinuation.java b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/ContextContinuation.java new file mode 100644 index 000000000..a94ae6d65 --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/ContextContinuation.java @@ -0,0 +1,597 @@ +/* ContextContinuation.java -- RMI naming context + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.naming.jndi.url.rmi; + +import java.rmi.AccessException; +import java.rmi.AlreadyBoundException; +import java.rmi.NotBoundException; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.util.Hashtable; +import java.util.Map; +import java.util.Properties; + +import javax.naming.CommunicationException; +import javax.naming.Context; +import javax.naming.InvalidNameException; +import javax.naming.Name; +import javax.naming.NameAlreadyBoundException; +import javax.naming.NameNotFoundException; +import javax.naming.NameParser; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.OperationNotSupportedException; + +/** + * The implementation of the RMI URL context. This context connects + * + * @author Audrius Meskauskas + */ +public class ContextContinuation implements Context +{ + /** + * The default registry location. + */ + public static final String DEFAULT_REGISTRY_LOCATION = "rmi://localhost:1099"; + + /** + * The local or remote RMI registry, performing the actual work for this + * context. + */ + Registry registry; + + /** + * The properties. + */ + Properties properties; + + /** + * The flag, indicating, that the lookup methods were called before. + * If the lookup methods were called before, the existing ORB cannot be + * destroyed, as references to the existing objects will become + * unfunctional. + */ + boolean lookupCalled; + + /** + * Add new environment property to the environment of this context. Both name + * and value of the new property must not be null. If the property is already + * defined, is current value is replaced by the propVal. This method replaces + * the registry. The new registry will be lazily instantiated on the first + * call. + * + * @param key + * the name of the new property + * @param value + * the value of the new property + * @return the previous value of this property or null if the property has not + * been previously defined + */ + public Object addToEnvironment(String key, Object value) + { + removeRegistry(); + if (key == null || value == null) + throw new NullPointerException(); + return properties.put(key, value); + } + + /** + * Returns the environment, associated with this naming context. The returned + * table should never be modified by the caller (the registry would not be updated + * in such case). Use {@link #addToEnvironment} and + * {@link #removeFromEnvironment} to modify the environement, if needed. + * + * @return the table, representing the environment of this context + * @throws NamingException + */ + public Hashtable getEnvironment() throws NamingException + { + return properties; + } + + /** + * Removes the property with the given name from the environment. Returns + * without action if this property is not defined. Replaces the ORB, + * constructing the new ORB with the changes set of properties (you can + * replace the CORBA implementation provider, for instance). The new ORB will + * be lazily instantiated on the first call. + * + * @param propName + * the name of the property being removed. + * @return the value of the property that has been removed or null if the + * property was not defined. + * @throws NamingException + */ + public Object removeFromEnvironment(String propName) throws NamingException + { + removeRegistry(); + return properties.remove(propName); + } + + /** + * Remove the current registry reference. + */ + public void removeRegistry() + { + registry = null; + } + + /** + * Get the cached or new registry reference. + * + * @return the registry reference, either cached or new. + */ + public Registry getRegistry() throws NamingException + { + if (registry == null) + { + String address = properties.getProperty(Context.PROVIDER_URL, + DEFAULT_REGISTRY_LOCATION); + + // The format like rmi://localhost:1099 is expected. Parse. + if (!address.startsWith("rmi://")) + throw new InvalidNameException(address); + + String a = address.substring("rmi://".length()); + + // The colon, if present, indicates the start of the port number. + int colon = a.lastIndexOf(':'); + int port; + + try + { + if (colon >=0) + { + port = Integer.parseInt(a.substring(colon+1)); + a = a.substring(0, colon); + } + else + port = Registry.REGISTRY_PORT; + } + catch (NumberFormatException e1) + { + throw new InvalidNameException(address); + } + + try + { + registry = LocateRegistry.getRegistry(a, port); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + } + return registry; + } + + /** + * Create the rmi url context that works, talking with the given RMI registry. + * + * @param props + * the properties for this context + * @param initialRegistry + * the initial value of the registry + */ + public ContextContinuation(Map props, Registry initialRegistry) + { + properties = new Properties(); + if (props != null) + properties.putAll(props); + registry = initialRegistry; + } + + /** + * Bind the given name into this context. The .toString() is called to + * convert into the string representation, required by RMI registry. + * + * @throws NamingException if the object is not an instance of Remote + */ + public void bind(Name name, Object obj) throws NamingException + { + bind(name.toString(), obj); + } + + /** + * Bind the given name into this context. + */ + public void bind(String name, Object obj) throws NamingException + { + try + { + getRegistry().bind(name, (Remote) obj); + } + catch (AccessException e) + { + throw new NamingException("access:"+e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (AlreadyBoundException e) + { + throw new NameAlreadyBoundException(name); + } + catch (ClassCastException c) + { + throw new NamingException("Only Remote can be bound:" + + obj.getClass().getName()); + } + } + + /** + * Not supported. + */ + public Name composeName(Name name, Name prefix) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported. + */ + public String composeName(String name, String prefix) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. The only supported case is an + * empty name (returns the cloned instance of self). + */ + public Context createSubcontext(Name name) throws NamingException + { + if (name.size() == 0) + return new rmiURLContext(properties); + else + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. The only supported case is an + * empty name (returns the cloned instance of self). + */ + public Context createSubcontext(String name) throws NamingException + { + if (name.length() == 0) + return new rmiURLContext(properties); + else + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. + */ + public void destroySubcontext(Name name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. + */ + public void destroySubcontext(String name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Returns the naming service URL, same that was passed vie + * {@link Context#PROVIDER_URL}. + */ + public String getNameInNamespace() throws NamingException + { + return properties.getProperty(Context.PROVIDER_URL, + DEFAULT_REGISTRY_LOCATION); + } + + /** + * Not supported, this context never parses any names. + */ + public NameParser getNameParser(Name name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported, this context never parses any names. + */ + public NameParser getNameParser(String name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * List existing bindings of this context (the parameter must be empty name, + * indicating the root context). The class name of the returned name class + * pairs is "Remote", as this "quick preview" method should probably not call + * the naming service again. Use listBindings if more details are required. + */ + public NamingEnumeration list(Name name) throws NamingException + { + if (name.size() > 0) + throw new OperationNotSupportedException("Only empty name is accepted"); + return list(""); + } + + /** + * List existing bindings of this context (the parameter must be empty string, + * indicating the root context). The class name of the returned name class + * pairs is "Remote", as this "quick preview" method should probably not call + * the naming service again. Use listBindings if more details are required. + */ + public NamingEnumeration list(String name) throws NamingException + { + if (name.length() > 0) + throw new OperationNotSupportedException("Only empty name is accepted"); + + try + { + return new ListEnumeration(getRegistry().list()); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * List existing bindings of this context (the parameter must be empty name, + * indicating the root context). + */ + public NamingEnumeration listBindings(Name name) throws NamingException + { + if (name.size() > 0) + throw new OperationNotSupportedException("Only empty name is accepted"); + return listBindings(""); + } + + /** + * List existing bindings of this context (the parameter must be empty name, + * indicating the root context). + */ + public NamingEnumeration listBindings(String name) throws NamingException + { + if (name.length() > 0) + throw new OperationNotSupportedException("Only empty name is accepted"); + + try + { + Registry r = getRegistry(); + return new ListBindingsEnumeration(r.list(), r); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Not supported. + */ + public Object lookupLink(Name name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported. + */ + public Object lookupLink(String name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Rebinds this object. + * + * @param name + * the object name (.toString()) is used to convert into string + * representation. + * @param obj + * object (must be an instance of Remote). + */ + public void rebind(Name name, Object obj) throws NamingException + { + rebind(name.toString(), obj); + } + + /** + * Rebinds this object. + * + * @param name + * the object name. + * @param obj + * object (must be an instance of Remote). + */ + public void rebind(String name, Object obj) throws NamingException + { + try + { + getRegistry().rebind(name, (Remote) obj); + } + catch (AccessException e) + { + throw new NamingException("access:"+e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (ClassCastException c) + { + throw new NamingException("Only Remote can be bound:" + + obj.getClass().getName()); + } + } + + /** + * Renames the object. If the new name is already bound in the given context, + * the {@link AlreadyBoundException} is thrown and the oldName binding is + * preserved. + */ + public void rename(Name oldName, Name newName) throws NamingException + { + rename(oldName.toString(), newName.toString()); + } + + /** + * Renames the object. If the new name is already bound in the given context, + * the {@link AlreadyBoundException} is thrown and the oldName binding is + * preserved. + */ + public synchronized void rename(String oldName, String newName) + throws NamingException + { + try + { + Registry r = getRegistry(); + Remote object = r.lookup(oldName); + r.unbind(oldName); + try + { + r.bind(newName, object); + } + catch (AlreadyBoundException e) + { + // Bind it back. + try + { + r.bind(oldName, object); + } + catch (AlreadyBoundException e1) + { + // We have just removed this name. + throw new InternalError(); + } + throw new NameAlreadyBoundException(newName); + } + } + catch (AccessException e) + { + throw new NamingException(e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (NotBoundException e) + { + throw new CommunicationException(e.toString()); + } + } + + /** + * Unbind the object. + */ + public void unbind(Name name) throws NamingException + { + unbind(name.toString()); + } + + /** + * Unbind the object. + */ + public void unbind(String name) throws NamingException + { + try + { + getRegistry().unbind(name); + } + catch (AccessException e) + { + throw new NamingException(e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (NotBoundException e) + { + throw new CommunicationException(e.toString()); + } + } + + /** + * Release the associated resources. + */ + public void close() throws NamingException + { + removeRegistry(); + } + + /** + * Resolve the object by name. + * + * @param name + * the object name, .toString() is used to get the string + * representation. + */ + public Object lookup(Name name) throws NamingException + { + return lookup(name.toString()); + } + + /** + * Resolve the object by name + * + * @param name the object name. + */ + public Object lookup(String name) throws NamingException + { + try + { + return getRegistry().lookup(name); + } + catch (AccessException e) + { + throw new NamingException(e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (NotBoundException e) + { + throw new NameNotFoundException(name); + } + } +} diff --git a/libjava/classpath/gnu/javax/naming/jndi/url/rmi/ListBindingsEnumeration.java b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/ListBindingsEnumeration.java new file mode 100644 index 000000000..6ac4788d0 --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/ListBindingsEnumeration.java @@ -0,0 +1,97 @@ +/* ListBindingsEnumeration.java -- handles rmi: urls + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.naming.jndi.url.rmi; + +import java.rmi.registry.Registry; + +import javax.naming.NamingEnumeration; + +/** + * Iterates over bindings, obtaining values first from the binding list and then + * from the binding iterator. + * + * @author Audrius Meskauskas + */ +public class ListBindingsEnumeration extends RmiNamingEnumeration implements + NamingEnumeration +{ + /** + * The naming service, to resolve the objects. + */ + Registry service; + + /** + * Create the new enumeration + * + * @param bindings + * the list of the bound names + * @param aService + * the RMI naming service, used to get the bound values. + */ + public ListBindingsEnumeration(String [] bindings, + Registry aService) + { + super(bindings); + service = aService; + } + + /** + * Convert from the CORBA binding into the javax.naming binding. As the CORBA + * naming service binding does not contain the object itself, this method + * makes the additional calls to the naming service. + * + * @param binding + * the binding to convert + * @return the value, that must be returned by the {@link #next()}. + */ + public Object convert(String binding) + { + try + { + Object object = service.lookup(binding); + return new javax.naming.Binding(binding, object); + } + catch (Exception e) + { + // Probably was removed by the concurent thread. + return null; + } + } + +} diff --git a/libjava/classpath/gnu/javax/naming/jndi/url/rmi/ListEnumeration.java b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/ListEnumeration.java new file mode 100644 index 000000000..b64ca87ea --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/ListEnumeration.java @@ -0,0 +1,80 @@ +/* ListEnumeration.java -- handles rmi: urls + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.naming.jndi.url.rmi; + +import java.rmi.Remote; + +import javax.naming.NameClassPair; +import javax.naming.NamingEnumeration; + +/** + * Iterates over name class pairs, obtaining values first from the binding list + * and then from the binding iterator. + * + * @author Audrius Meskauskas + */ +public class ListEnumeration extends RmiNamingEnumeration implements + NamingEnumeration +{ + /** + * Create the new enumeration + * + * @param bindings + * the array of the binding names, returned by the RMI registry. + */ + public ListEnumeration(String [] bindings) + { + super(bindings); + } + + /** + * Convert from the binding name into the {@link NameClassPair} that this + * enumeration should return. + * + * @param binding + * the binding to convert + * @return the value, that must be returned by the {@link #next()}. + */ + public Object convert(String binding) + { + NameClassPair pair = new NameClassPair(binding, Remote.class.getName()); + return pair; + } + +} diff --git a/libjava/classpath/gnu/javax/naming/jndi/url/rmi/RmiContinuation.java b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/RmiContinuation.java new file mode 100644 index 000000000..c8e6a158a --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/RmiContinuation.java @@ -0,0 +1,594 @@ +/* RmiContinuation.java -- RMI naming context + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.naming.jndi.url.rmi; + +import java.rmi.AccessException; +import java.rmi.AlreadyBoundException; +import java.rmi.NotBoundException; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.util.Hashtable; +import java.util.Map; +import java.util.Properties; + +import javax.naming.CommunicationException; +import javax.naming.Context; +import javax.naming.InvalidNameException; +import javax.naming.Name; +import javax.naming.NameAlreadyBoundException; +import javax.naming.NameNotFoundException; +import javax.naming.NameParser; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.OperationNotSupportedException; + +/** + * The implementation of the RMI URL context. This context connects + * + * @author Audrius Meskauskas + */ +public class RmiContinuation implements Context +{ + /** + * The default registry location. + */ + public static final String DEFAULT_REGISTRY_LOCATION = "rmi://localhost:1099"; + + /** + * The local or remote RMI registry, performing the actual work for this + * context. + */ + Registry registry; + + /** + * The properties. + */ + Properties properties; + + /** + * The flag, indicating, that the lookup methods were called before. + * If the lookup methods were called before, the existing ORB cannot be + * destroyed, as references to the existing objects will become + * unfunctional. + */ + boolean lookupCalled; + + /** + * Add new environment property to the environment of this context. Both name + * and value of the new property must not be null. If the property is already + * defined, is current value is replaced by the propVal. This method replaces + * the registry. The new registry will be lazily instantiated on the first + * call. + * + * @param key + * the name of the new property + * @param value + * the value of the new property + * @return the previous value of this property or null if the property has not + * been previously defined + */ + public Object addToEnvironment(String key, Object value) + { + removeRegistry(); + if (key == null || value == null) + throw new NullPointerException(); + return properties.put(key, value); + } + + /** + * Returns the environment, associated with this naming context. The returned + * table should never be modified by the caller (the registry would not be updated + * in such case). Use {@link #addToEnvironment} and + * {@link #removeFromEnvironment} to modify the environement, if needed. + * + * @return the table, representing the environment of this context + * @throws NamingException + */ + public Hashtable getEnvironment() throws NamingException + { + return properties; + } + + /** + * Removes the property with the given name from the environment. Returns + * without action if this property is not defined. Replaces the ORB, + * constructing the new ORB with the changes set of properties (you can + * replace the CORBA implementation provider, for instance). The new ORB will + * be lazily instantiated on the first call. + * + * @param propName + * the name of the property being removed. + * @return the value of the property that has been removed or null if the + * property was not defined. + * @throws NamingException + */ + public Object removeFromEnvironment(String propName) throws NamingException + { + removeRegistry(); + return properties.remove(propName); + } + + /** + * Remove the current registry reference. + */ + public void removeRegistry() + { + registry = null; + } + + /** + * Get the cached or new registry reference. + * + * @return the registry reference, either cached or new. + */ + public Registry getRegistry() throws NamingException + { + if (registry == null) + { + String address = properties.getProperty(Context.PROVIDER_URL, + DEFAULT_REGISTRY_LOCATION); + + // The format like rmi://localhost:1099 is expected. Parse. + if (!address.startsWith("rmi://")) + throw new InvalidNameException(address); + + String a = address.substring("rmi://".length()); + + // The colon, if present, indicates the start of the port number. + int colon = a.lastIndexOf(':'); + int port; + + try + { + if (colon >=0) + { + port = Integer.parseInt(a.substring(colon+1)); + a = a.substring(0, colon); + } + else + port = Registry.REGISTRY_PORT; + } + catch (NumberFormatException e1) + { + throw new InvalidNameException(address); + } + + try + { + registry = LocateRegistry.getRegistry(a, port); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + } + return registry; + } + + /** + * Create the rmi url context that works, talking with the given RMI registry. + * + * @param props + * the properties for this context + */ + public RmiContinuation(Map props) + { + properties = new Properties(); + if (props != null) + properties.putAll(props); + } + + /** + * Bind the given name into this context. The .toString() is called to + * convert into the string representation, required by RMI registry. + * + * @throws NamingException if the object is not an instance of Remote + */ + public void bind(Name name, Object obj) throws NamingException + { + bind(name.toString(), obj); + } + + /** + * Bind the given name into this context. + */ + public void bind(String name, Object obj) throws NamingException + { + try + { + getRegistry().bind(name, (Remote) obj); + } + catch (AccessException e) + { + throw new NamingException("access:"+e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (AlreadyBoundException e) + { + throw new NameAlreadyBoundException(name); + } + catch (ClassCastException c) + { + throw new NamingException("Only Remote can be bound:" + + obj.getClass().getName()); + } + } + + /** + * Not supported. + */ + public Name composeName(Name name, Name prefix) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported. + */ + public String composeName(String name, String prefix) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. The only supported case is an + * empty name (returns the cloned instance of self). + */ + public Context createSubcontext(Name name) throws NamingException + { + if (name.size() == 0) + return new RmiContinuation(properties); + else + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. The only supported case is an + * empty name (returns the cloned instance of self). + */ + public Context createSubcontext(String name) throws NamingException + { + if (name.length() == 0) + return new RmiContinuation(properties); + else + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. + */ + public void destroySubcontext(Name name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. + */ + public void destroySubcontext(String name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Returns the naming service URL, same that was passed vie + * {@link Context#PROVIDER_URL}. + */ + public String getNameInNamespace() throws NamingException + { + return properties.getProperty(Context.PROVIDER_URL, + DEFAULT_REGISTRY_LOCATION); + } + + /** + * Not supported, this context never parses any names. + */ + public NameParser getNameParser(Name name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported, this context never parses any names. + */ + public NameParser getNameParser(String name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * List existing bindings of this context (the parameter must be empty name, + * indicating the root context). The class name of the returned name class + * pairs is "Remote", as this "quick preview" method should probably not call + * the naming service again. Use listBindings if more details are required. + */ + public NamingEnumeration list(Name name) throws NamingException + { + if (name.size() > 0) + throw new OperationNotSupportedException("Only empty name is accepted"); + return list(""); + } + + /** + * List existing bindings of this context (the parameter must be empty string, + * indicating the root context). The class name of the returned name class + * pairs is "Remote", as this "quick preview" method should probably not call + * the naming service again. Use listBindings if more details are required. + */ + public NamingEnumeration list(String name) throws NamingException + { + if (name.length() > 0) + throw new OperationNotSupportedException("Only empty name is accepted"); + + try + { + return new ListEnumeration(getRegistry().list()); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * List existing bindings of this context (the parameter must be empty name, + * indicating the root context). + */ + public NamingEnumeration listBindings(Name name) throws NamingException + { + if (name.size() > 0) + throw new OperationNotSupportedException("Only empty name is accepted"); + return listBindings(""); + } + + /** + * List existing bindings of this context (the parameter must be empty name, + * indicating the root context). + */ + public NamingEnumeration listBindings(String name) throws NamingException + { + if (name.length() > 0) + throw new OperationNotSupportedException("Only empty name is accepted"); + + try + { + Registry r = getRegistry(); + return new ListBindingsEnumeration(r.list(), r); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Not supported. + */ + public Object lookupLink(Name name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported. + */ + public Object lookupLink(String name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Rebinds this object. + * + * @param name + * the object name (.toString()) is used to convert into string + * representation. + * @param obj + * object (must be an instance of Remote). + */ + public void rebind(Name name, Object obj) throws NamingException + { + rebind(name.toString(), obj); + } + + /** + * Rebinds this object. + * + * @param name + * the object name. + * @param obj + * object (must be an instance of Remote). + */ + public void rebind(String name, Object obj) throws NamingException + { + try + { + getRegistry().rebind(name, (Remote) obj); + } + catch (AccessException e) + { + throw new NamingException("access:"+e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (ClassCastException c) + { + throw new NamingException("Only Remote can be bound:" + + obj.getClass().getName()); + } + } + + /** + * Renames the object. If the new name is already bound in the given context, + * the {@link AlreadyBoundException} is thrown and the oldName binding is + * preserved. + */ + public void rename(Name oldName, Name newName) throws NamingException + { + rename(oldName.toString(), newName.toString()); + } + + /** + * Renames the object. If the new name is already bound in the given context, + * the {@link AlreadyBoundException} is thrown and the oldName binding is + * preserved. + */ + public synchronized void rename(String oldName, String newName) + throws NamingException + { + try + { + Registry r = getRegistry(); + Remote object = r.lookup(oldName); + r.unbind(oldName); + try + { + r.bind(newName, object); + } + catch (AlreadyBoundException e) + { + // Bind it back. + try + { + r.bind(oldName, object); + } + catch (AlreadyBoundException e1) + { + // We have just removed this name. + throw new InternalError(); + } + throw new NameAlreadyBoundException(newName); + } + } + catch (AccessException e) + { + throw new NamingException(e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (NotBoundException e) + { + throw new CommunicationException(e.toString()); + } + } + + /** + * Unbind the object. + */ + public void unbind(Name name) throws NamingException + { + unbind(name.toString()); + } + + /** + * Unbind the object. + */ + public void unbind(String name) throws NamingException + { + try + { + getRegistry().unbind(name); + } + catch (AccessException e) + { + throw new NamingException(e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (NotBoundException e) + { + throw new CommunicationException(e.toString()); + } + } + + /** + * Release the associated resources. + */ + public void close() throws NamingException + { + removeRegistry(); + } + + /** + * Resolve the object by name. + * + * @param name + * the object name, .toString() is used to get the string + * representation. + */ + public Object lookup(Name name) throws NamingException + { + return lookup(name.toString()); + } + + /** + * Resolve the object by name + * + * @param name the object name. + */ + public Object lookup(String name) throws NamingException + { + try + { + return getRegistry().lookup(name); + } + catch (AccessException e) + { + throw new NamingException(e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (NotBoundException e) + { + throw new NameNotFoundException(name); + } + } +} diff --git a/libjava/classpath/gnu/javax/naming/jndi/url/rmi/RmiNamingEnumeration.java b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/RmiNamingEnumeration.java new file mode 100644 index 000000000..a75896272 --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/RmiNamingEnumeration.java @@ -0,0 +1,130 @@ +/* RmiNamingEnumeration.java -- handles rmi: urls + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.naming.jndi.url.rmi; + +import java.util.NoSuchElementException; + +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; + +/** + * Iterates over name class pairs, obtaining values first from the binding list + * and then from the binding iterator. + * + * @author Audrius Meskauskas + */ +public abstract class RmiNamingEnumeration implements NamingEnumeration +{ + /** + * The array of bindings, returned at once. + */ + String[] list; + + /** + * The position of the element in the binding list, that must be returned + * during the subsequent call of the next(). If this field is grater or equal + * to the lenght of the list, the subsequent values must be requested from the + * iterator. + */ + int p; + + RmiNamingEnumeration(String[] bindingList) + { + list = bindingList; + } + + /** + * Convert from the CORBA binding into that this enumeration should return. + * + * @param binding + * the binding to convert + * @return the value, that must be returned by the {@link #next()}. + */ + public abstract Object convert(String binding); + + /** + * Checks if there are more elements to return. + * + * @throws NamingException + * never + */ + public boolean hasMore() throws NamingException + { + return hasMoreElements(); + } + + /** + * Returns the next element. + * + * @throws NamingException + * never + */ + public Object next() throws NamingException + { + return nextElement(); + } + + /** + * Checks if there are more elements to return. + */ + public boolean hasMoreElements() + { + return p < list.length; + } + + /** + * Returns the next element. + */ + public Object nextElement() + { + if (p < list.length) + return convert(list[p++]); + else + throw new NoSuchElementException(); + } + + /** + * Nothing to do in this method. + */ + public void close() + { + // Nothing to do here. + } + +} diff --git a/libjava/classpath/gnu/javax/naming/jndi/url/rmi/rmiURLContext.java b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/rmiURLContext.java new file mode 100644 index 000000000..11f7265a6 --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/rmiURLContext.java @@ -0,0 +1,637 @@ +/* rmiURLContext.java -- RMI naming context + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.naming.jndi.url.rmi; + +import java.rmi.AccessException; +import java.rmi.AlreadyBoundException; +import java.rmi.NotBoundException; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.util.Hashtable; +import java.util.Map; +import java.util.Properties; +import java.util.WeakHashMap; + +import javax.naming.CommunicationException; +import javax.naming.Context; +import javax.naming.InvalidNameException; +import javax.naming.Name; +import javax.naming.NameAlreadyBoundException; +import javax.naming.NameNotFoundException; +import javax.naming.NameParser; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.OperationNotSupportedException; + +/** + * The implementation of the RMI URL context. This context connects + * + * @author Audrius Meskauskas + */ +public class rmiURLContext implements Context +{ + /** + * The default registry location. + */ + public static final String DEFAULT_REGISTRY_LOCATION = "rmi://localhost:1099"; + + /** + * The registry cache, maps the registry URL's to they instances. The + * obtained registries are reused, as newly obtaining them may cause the + * resource leak. + */ + static WeakHashMap registryCache = new WeakHashMap(); + + /** + * The properties. + */ + Properties properties; + + /** + * The flag, indicating, that the lookup methods were called before. + * If the lookup methods were called before, the existing ORB cannot be + * destroyed, as references to the existing objects will become + * unfunctional. + */ + boolean lookupCalled; + + /** + * Add new environment property to the environment of this context. Both name + * and value of the new property must not be null. If the property is already + * defined, is current value is replaced by the propVal. This method replaces + * the registry. The new registry will be lazily instantiated on the first + * call. + * + * @param key + * the name of the new property + * @param value + * the value of the new property + * @return the previous value of this property or null if the property has not + * been previously defined + */ + public Object addToEnvironment(String key, Object value) + { + if (key == null || value == null) + throw new NullPointerException(); + return properties.put(key, value); + } + + /** + * Returns the environment, associated with this naming context. The returned + * table should never be modified by the caller (the registry would not be updated + * in such case). Use {@link #addToEnvironment} and + * {@link #removeFromEnvironment} to modify the environement, if needed. + * + * @return the table, representing the environment of this context + * @throws NamingException + */ + public Hashtable getEnvironment() throws NamingException + { + return properties; + } + + /** + * Removes the property with the given name from the environment. Returns + * without action if this property is not defined. Replaces the ORB, + * constructing the new ORB with the changes set of properties (you can + * replace the CORBA implementation provider, for instance). The new ORB will + * be lazily instantiated on the first call. + * + * @param propName + * the name of the property being removed. + * @return the value of the property that has been removed or null if the + * property was not defined. + * @throws NamingException + */ + public Object removeFromEnvironment(String propName) throws NamingException + { + return properties.remove(propName); + } + + /** + * Get the cached or new registry reference. + * + * @return the registry reference, either cached or new. + */ + public Registry getRegistry(String netAddress) throws NamingException + { + Registry registry; + + synchronized (registryCache) + { + registry = (Registry) registryCache.get(netAddress); + } + + if (registry == null) + { + // The colon, if present, indicates the start of the port number. + int colon = netAddress.lastIndexOf(':'); + int port; + + try + { + if (colon >= 0) + { + port = Integer.parseInt(netAddress.substring(colon + 1)); + netAddress = netAddress.substring(0, colon); + } + else + port = Registry.REGISTRY_PORT; + } + catch (NumberFormatException e1) + { + throw new InvalidNameException(netAddress); + } + + try + { + registry = LocateRegistry.getRegistry(netAddress, port); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + + synchronized (registryCache) + { + registryCache.put(netAddress, registry); + } + } + return registry; + } + + /** + * Create the rmi url context that works, talking with the given RMI registry. + * + * @param props + * the properties for this context + */ + public rmiURLContext(Map props) + { + properties = new Properties(); + if (props != null) + properties.putAll(props); + } + + /** + * Bind the given name into this context. The .toString() is called to + * convert into the string representation, required by RMI registry. + * + * @throws NamingException if the object is not an instance of Remote + */ + public void bind(Name name, Object obj) throws NamingException + { + bind(name.toString(), obj); + } + + /** + * Bind the given name into this context. + */ + public void bind(String name, Object obj) throws NamingException + { + try + { + String [] n = split(name); + getRegistry(n[0]).bind(n[1], (Remote) obj); + } + catch (AccessException e) + { + throw new NamingException("access:"+e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (AlreadyBoundException e) + { + throw new NameAlreadyBoundException(name); + } + catch (ClassCastException c) + { + throw new NamingException("Only Remote can be bound:" + + obj.getClass().getName()); + } + } + + /** + * Not supported. + */ + public Name composeName(Name name, Name prefix) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported. + */ + public String composeName(String name, String prefix) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. The only supported case is an + * empty name (returns the cloned instance of self). + */ + public Context createSubcontext(Name name) throws NamingException + { + if (name.size() == 0) + return new rmiURLContext(properties); + else + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. The only supported case is an + * empty name (returns the cloned instance of self). + */ + public Context createSubcontext(String name) throws NamingException + { + if (name.length() == 0) + return new rmiURLContext(properties); + else + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. + */ + public void destroySubcontext(Name name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. + */ + public void destroySubcontext(String name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Returns the naming service URL, same that was passed vie + * {@link Context#PROVIDER_URL}. + */ + public String getNameInNamespace() throws NamingException + { + return properties.getProperty(Context.PROVIDER_URL, + DEFAULT_REGISTRY_LOCATION); + } + + /** + * Not supported, this context never parses any names. + */ + public NameParser getNameParser(Name name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported, this context never parses any names. + */ + public NameParser getNameParser(String name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * List existing bindings of this context (the parameter must be empty name, + * indicating the root context). The class name of the returned name class + * pairs is "Remote", as this "quick preview" method should probably not call + * the naming service again. Use listBindings if more details are required. + */ + public NamingEnumeration list(Name name) throws NamingException + { + return list(name); + } + + /** + * List existing bindings of thie given registry.The class name of the + * returned name class pairs is "Remote", as this "quick preview" method + * should probably not call the naming service again. Use listBindings if more + * details are required. + */ + public NamingEnumeration list(String name) throws NamingException + { + try + { + String [] n = split(name); + if (n[1].length() > 0) + throw new InvalidNameException(name+", the name part must be empty"); + return new ListEnumeration(getRegistry(n[0]).list()); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * List existing bindings of this context (the parameter must be empty name, + * indicating the root context). + */ + public NamingEnumeration listBindings(Name name) throws NamingException + { + return listBindings(name.toString()); + } + + /** + * List existing bindings of this context. + */ + public NamingEnumeration listBindings(String name) throws NamingException + { + try + { + String [] n = split(name); + if (n[1].length() > 0) + throw new InvalidNameException(name+", the name part must be empty"); + + Registry r = getRegistry(n[0]); + return new ListBindingsEnumeration(r.list(), r); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Returns the naming service context under the given address, wrapped as + * Context. + */ + public Object lookupLink(Name name) throws NamingException + { + return lookupLink(name.toString()); + } + + /** + * Returns the naming service context under the given address, + * wrapped as Context. + */ + public Object lookupLink(String name) throws NamingException + { + return new ContextContinuation(properties, getRegistry(name)); + } + + /** + * Rebinds this object. + * + * @param name + * the object name (.toString()) is used to convert into string + * representation. + * @param obj + * object (must be an instance of Remote). + */ + public void rebind(Name name, Object obj) throws NamingException + { + rebind(name.toString(), obj); + } + + /** + * Rebinds this object. + * + * @param name + * the object name. + * @param obj + * object (must be an instance of Remote). + */ + public void rebind(String name, Object obj) throws NamingException + { + try + { + String [] n = split(name); + getRegistry(n[0]).rebind(n[1], (Remote) obj); + } + catch (AccessException e) + { + throw new NamingException("access:"+e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (ClassCastException c) + { + throw new NamingException("Only Remote can be bound:" + + obj.getClass().getName()); + } + } + + /** + * Renames the object. If the new name is already bound in the given context, + * the {@link AlreadyBoundException} is thrown and the oldName binding is + * preserved. + */ + public void rename(Name oldName, Name newName) throws NamingException + { + rename(oldName.toString(), newName.toString()); + } + + /** + * Renames the object. If the new name is already bound in the given context, + * the {@link AlreadyBoundException} is thrown and the oldName binding is + * preserved. + */ + public synchronized void rename(String oldName, String newName) + throws NamingException + { + try + { + String [] n = split(oldName); + Registry r = getRegistry(n[0]); + Remote object = r.lookup(n[1]); + r.unbind(oldName); + try + { + String [] n2 = split(newName); + Registry r2 = getRegistry(n2[0]); + r2.bind(n2[1], object); + } + catch (AlreadyBoundException e) + { + // Bind it back. + try + { + r.bind(oldName, object); + } + catch (AlreadyBoundException e1) + { + // We have just removed this name. + throw new InternalError(); + } + throw new NameAlreadyBoundException(newName); + } + } + catch (AccessException e) + { + throw new NamingException(e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (NotBoundException e) + { + throw new CommunicationException(e.toString()); + } + } + + /** + * Unbind the object. + */ + public void unbind(Name name) throws NamingException + { + unbind(name.toString()); + } + + /** + * Unbind the object. + */ + public void unbind(String name) throws NamingException + { + try + { + String [] n = split(name); + getRegistry(n[0]).unbind(n[1]); + } + catch (AccessException e) + { + throw new NamingException(e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (NotBoundException e) + { + throw new CommunicationException(e.toString()); + } + } + + /** + * Release the associated resources. + */ + public void close() throws NamingException + { + } + + /** + * Resolve the object by name. + * + * @param name + * the object name, .toString() is used to get the string + * representation. + */ + public Object lookup(Name name) throws NamingException + { + return lookup(name.toString()); + } + + /** + * Resolve the object by name + * + * @param name the object name. + */ + public Object lookup(String name) throws NamingException + { + try + { + String [] n = split(name); + return getRegistry(n[0]).lookup(n[1]); + } + catch (AccessException e) + { + throw new NamingException(e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (NotBoundException e) + { + throw new NameNotFoundException(name); + } + } + + /** + * Split the given rmi address into the network address and naming service + * name. + * + * @param address + * the address to split + * @return the two member array, lower being the network address of the naming + * service and upper being the naming service name + * @throws NamingException + * if the name is invalid + */ + public String[] split(String address) throws NamingException + { + // The format like rmi://localhost:1099/name is expected. Parse. + if (!address.startsWith("rmi://")) + throw new InvalidNameException( + address + + " should be like 'rmi://localhost:1099/name'"); + + String a = address.substring("rmi://".length()); + + // The suffix starts after the first slash from the rmi:// + int sfx = a.indexOf('/'); + + // Handle the possible escape + while (sfx > 0 && a.charAt(sfx - 1) == '\\') + sfx = a.indexOf('/', sfx + 1); + + String net; + String name; + if (sfx >= 0) + { + net = a.substring(0, sfx); + name = a.substring(sfx + 1); + } + else + { + net = a; + name = ""; + } + + return new String[] { net, name }; + } +} diff --git a/libjava/classpath/gnu/javax/naming/jndi/url/rmi/rmiURLContextFactory.java b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/rmiURLContextFactory.java new file mode 100644 index 000000000..ce0471d36 --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/rmiURLContextFactory.java @@ -0,0 +1,66 @@ +/* rmiURLContextFactory.java -- handles RMI naming context + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.naming.jndi.url.rmi; + +import java.util.Hashtable; + +import javax.naming.Context; +import javax.naming.Name; +import javax.naming.spi.ObjectFactory; + +/** + * Find the RMI URL context. This factory checks the Context.PROVIDER_URL + * property for the address of the RMI naming service and creates the + * context that operates talking with this naming service. If such property + * is missing, "rmi://localhost:1099" is assumed. + * + * @author Audrius Meskauskas (audriusa@Bioinformatics.org) + */ +public class rmiURLContextFactory implements ObjectFactory +{ + + /** + * Create a new instance of the context. + */ + public Object getObjectInstance(Object refObj, Name name, Context nameCtx, + Hashtable environment) + { + return new rmiURLContext(environment); + } + +} diff --git a/libjava/classpath/gnu/javax/net/ssl/AbstractSessionContext.java b/libjava/classpath/gnu/javax/net/ssl/AbstractSessionContext.java new file mode 100644 index 000000000..96a4e6dd0 --- /dev/null +++ b/libjava/classpath/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; +} diff --git a/libjava/classpath/gnu/javax/net/ssl/EntropySource.java b/libjava/classpath/gnu/javax/net/ssl/EntropySource.java new file mode 100644 index 000000000..be840e5d6 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/EntropySource.java @@ -0,0 +1,62 @@ +/* EntropySource.java -- a source of random bits. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl; + +/** + * A generic interface for adding random bytes to an entropy pool. + */ +public interface EntropySource +{ + + /** + * Returns the estimated quality of this source. This value should be + * between 0 and 100 (the running quality is computed as a percentage, + * 100 percent being perfect-quality). + * + * @return The quality. + */ + double quality(); + + /** + * Returns a new buffer with the next random bytes to add. + * + * @return The next random bytes. + */ + byte[] nextBytes(); +} diff --git a/libjava/classpath/gnu/javax/net/ssl/NullManagerParameters.java b/libjava/classpath/gnu/javax/net/ssl/NullManagerParameters.java new file mode 100644 index 000000000..0e9337932 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/NullManagerParameters.java @@ -0,0 +1,56 @@ +/* NullManagerParameters.java -- parameters for empty managers. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl; + +import javax.net.ssl.ManagerFactoryParameters; + +/** + * This empty class can be used to initialize {@link + * javax.net.ssl.KeyManagerFactory} and {@link + * javax.net.ssl.TrustManagerFactory} instances for the ``JessieX509'' + * algorithm, for cases when no keys or trusted certificates are + * desired or needed. + * + *

This is the default manager parameters object used in {@link + * javax.net.ssl.KeyManagerFactory} instances if no key stores are + * specified through security properties. + */ +public final class NullManagerParameters implements ManagerFactoryParameters +{ +} diff --git a/libjava/classpath/gnu/javax/net/ssl/PreSharedKeyManager.java b/libjava/classpath/gnu/javax/net/ssl/PreSharedKeyManager.java new file mode 100644 index 000000000..2c9fd2aea --- /dev/null +++ b/libjava/classpath/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(); +} diff --git a/libjava/classpath/gnu/javax/net/ssl/PreSharedKeyManagerParameters.java b/libjava/classpath/gnu/javax/net/ssl/PreSharedKeyManagerParameters.java new file mode 100644 index 000000000..fe3c9e89b --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/PrivateCredentials.java b/libjava/classpath/gnu/javax/net/ssl/PrivateCredentials.java new file mode 100644 index 000000000..7fff253dd --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/PrivateCredentials.java @@ -0,0 +1,363 @@ +/* PrivateCredentials.java -- private key/certificate pairs. + Copyright (C) 2006, 2007 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl; + +import gnu.java.lang.CPStringBuilder; + +import java.io.EOFException; +import java.io.InputStream; +import java.io.IOException; + +import java.math.BigInteger; + +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.Security; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.spec.DSAPrivateKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.RSAPrivateCrtKeySpec; + +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; + +import javax.net.ssl.ManagerFactoryParameters; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; + +import gnu.javax.security.auth.callback.ConsoleCallbackHandler; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.mode.ModeFactory; +import gnu.javax.crypto.pad.WrongPaddingException; + +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.util.Base64; + +/** + * An instance of a manager factory parameters for holding a single + * certificate/private key pair, encoded in PEM format. + */ +public class PrivateCredentials implements ManagerFactoryParameters +{ + + // Fields. + // ------------------------------------------------------------------------- + + public static final String BEGIN_DSA = "-----BEGIN DSA PRIVATE KEY"; + public static final String END_DSA = "-----END DSA PRIVATE KEY"; + public static final String BEGIN_RSA = "-----BEGIN RSA PRIVATE KEY"; + public static final String END_RSA = "-----END RSA PRIVATE KEY"; + + private List privateKeys; + private List certChains; + + // Constructor. + // ------------------------------------------------------------------------- + + public PrivateCredentials() + { + privateKeys = new LinkedList(); + certChains = new LinkedList(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void add(InputStream certChain, InputStream privateKey) + throws CertificateException, InvalidKeyException, InvalidKeySpecException, + IOException, NoSuchAlgorithmException, WrongPaddingException + { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + Collection certs = cf.generateCertificates(certChain); + X509Certificate[] chain = (X509Certificate[]) certs.toArray(new X509Certificate[0]); + + String alg = null; + String line = readLine(privateKey); + String finalLine = null; + if (line.startsWith(BEGIN_DSA)) + { + alg = "DSA"; + finalLine = END_DSA; + } + else if (line.startsWith(BEGIN_RSA)) + { + alg = "RSA"; + finalLine = END_RSA; + } + else + throw new IOException("Unknown private key type."); + + boolean encrypted = false; + String cipher = null; + String salt = null; + CPStringBuilder base64 = new CPStringBuilder(); + while (true) + { + line = readLine(privateKey); + if (line == null) + throw new EOFException("premature end-of-file"); + else if (line.startsWith("Proc-Type: 4,ENCRYPTED")) + encrypted = true; + else if (line.startsWith("DEK-Info: ")) + { + int i = line.indexOf(','); + if (i < 0) + cipher = line.substring(10).trim(); + else + { + cipher = line.substring(10, i).trim(); + salt = line.substring(i + 1).trim(); + } + } + else if (line.startsWith(finalLine)) + break; + else if (line.length() > 0) + { + base64.append(line); + base64.append(System.getProperty("line.separator")); + } + } + + byte[] enckey = Base64.decode(base64.toString()); + if (encrypted) + { + enckey = decryptKey(enckey, cipher, toByteArray(salt)); + } + + DERReader der = new DERReader(enckey); + if (der.read().getTag() != DER.SEQUENCE) + throw new IOException("malformed DER sequence"); + der.read(); // version + + KeyFactory kf = KeyFactory.getInstance(alg); + KeySpec spec = null; + if (alg.equals("DSA")) + { + BigInteger p = (BigInteger) der.read().getValue(); + BigInteger q = (BigInteger) der.read().getValue(); + BigInteger g = (BigInteger) der.read().getValue(); + der.read(); // y + BigInteger x = (BigInteger) der.read().getValue(); + spec = new DSAPrivateKeySpec(x, p, q, g); + } + else + { + spec = new RSAPrivateCrtKeySpec( + (BigInteger) der.read().getValue(), // modulus + (BigInteger) der.read().getValue(), // pub exponent + (BigInteger) der.read().getValue(), // priv expenent + (BigInteger) der.read().getValue(), // prime p + (BigInteger) der.read().getValue(), // prime q + (BigInteger) der.read().getValue(), // d mod (p-1) + (BigInteger) der.read().getValue(), // d mod (q-1) + (BigInteger) der.read().getValue()); // coefficient + } + + privateKeys.add(kf.generatePrivate(spec)); + certChains.add(chain); + } + + public List getPrivateKeys() + { + if (isDestroyed()) + { + throw new IllegalStateException("this object is destroyed"); + } + return privateKeys; + } + + public List getCertChains() + { + return certChains; + } + + public void destroy() + { + privateKeys.clear(); + privateKeys = null; + } + + public boolean isDestroyed() + { + return (privateKeys == null); + } + + // Own methods. + // ------------------------------------------------------------------------- + + private String readLine(InputStream in) throws IOException + { + boolean eol_is_cr = System.getProperty("line.separator").equals("\r"); + CPStringBuilder str = new CPStringBuilder(); + while (true) + { + int i = in.read(); + if (i == -1) + { + if (str.length() > 0) + break; + else + return null; + } + else if (i == '\r') + { + if (eol_is_cr) + break; + } + else if (i == '\n') + break; + else + str.append((char) i); + } + return str.toString(); + } + + private byte[] decryptKey(byte[] ct, String cipher, byte[] salt) + throws IOException, InvalidKeyException, WrongPaddingException + { + byte[] pt = new byte[ct.length]; + IMode mode = null; + if (cipher.equals("DES-EDE3-CBC")) + { + mode = ModeFactory.getInstance("CBC", "TripleDES", 8); + HashMap attr = new HashMap(); + attr.put(IMode.KEY_MATERIAL, deriveKey(salt, 24)); + attr.put(IMode.IV, salt); + attr.put(IMode.STATE, new Integer(IMode.DECRYPTION)); + mode.init(attr); + } + else if (cipher.equals("DES-CBC")) + { + mode = ModeFactory.getInstance("CBC", "DES", 8); + HashMap attr = new HashMap(); + attr.put(IMode.KEY_MATERIAL, deriveKey(salt, 8)); + attr.put(IMode.IV, salt); + attr.put(IMode.STATE, new Integer(IMode.DECRYPTION)); + mode.init(attr); + } + else + throw new IllegalArgumentException("unknown cipher: " + cipher); + + for (int i = 0; i < ct.length; i += 8) + mode.update(ct, i, pt, i); + + int pad = pt[pt.length-1]; + if (pad < 1 || pad > 8) + throw new WrongPaddingException(); + for (int i = pt.length - pad; i < pt.length; i++) + { + if (pt[i] != pad) + throw new WrongPaddingException(); + } + + byte[] result = new byte[pt.length - pad]; + System.arraycopy(pt, 0, result, 0, result.length); + return result; + } + + private byte[] deriveKey(byte[] salt, int keylen) + throws IOException + { + CallbackHandler passwordHandler = new ConsoleCallbackHandler(); + try + { + Class c = Class.forName(Security.getProperty("jessie.password.handler")); + passwordHandler = (CallbackHandler) c.newInstance(); + } + catch (Exception x) { } + + PasswordCallback passwdCallback = + new PasswordCallback("Enter PEM passphrase: ", false); + try + { + passwordHandler.handle(new Callback[] { passwdCallback }); + } + catch (UnsupportedCallbackException uce) + { + throw new IOException("specified handler cannot handle passwords"); + } + char[] passwd = passwdCallback.getPassword(); + + IMessageDigest md5 = HashFactory.getInstance("MD5"); + byte[] key = new byte[keylen]; + int count = 0; + while (count < keylen) + { + for (int i = 0; i < passwd.length; i++) + md5.update((byte) passwd[i]); + md5.update(salt, 0, salt.length); + byte[] digest = md5.digest(); + int len = Math.min(digest.length, keylen - count); + System.arraycopy(digest, 0, key, count, len); + count += len; + if (count >= keylen) + break; + md5.reset(); + md5.update(digest, 0, digest.length); + } + passwdCallback.clearPassword(); + return key; + } + + private byte[] toByteArray(String hex) + { + hex = hex.toLowerCase(); + byte[] buf = new byte[hex.length() / 2]; + int j = 0; + for (int i = 0; i < buf.length; i++) + { + buf[i] = (byte) ((Character.digit(hex.charAt(j++), 16) << 4) | + Character.digit(hex.charAt(j++), 16)); + } + return buf; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/SRPManagerParameters.java b/libjava/classpath/gnu/javax/net/ssl/SRPManagerParameters.java new file mode 100644 index 000000000..a2a745e1b --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/SRPManagerParameters.java @@ -0,0 +1,81 @@ +/* SRPManagerParameters.java -- Wrapper for SRP PasswordFile. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl; + +import javax.net.ssl.ManagerFactoryParameters; +import gnu.javax.crypto.sasl.srp.PasswordFile; + +/** + * Instances of this class are used to initialize {@link + * javax.net.ssl.TrustManagerFactory} instances for the ``SRP'' algorithm. + */ +public class SRPManagerParameters implements ManagerFactoryParameters +{ + + // Field. + // ------------------------------------------------------------------------- + + private final PasswordFile file; + + // Constructor. + // ------------------------------------------------------------------------- + + /** + * Initializes these parameters with the specified SRP password file. + * + * @param file The SRP password file object. + * @throws NullPointerException if file is null. + */ + public SRPManagerParameters(PasswordFile file) + { + if (file == null) + { + throw new NullPointerException(); + } + this.file = file; + } + + // Instance method. + // ------------------------------------------------------------------------- + + public PasswordFile getPasswordFile() + { + return file; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/SRPTrustManager.java b/libjava/classpath/gnu/javax/net/ssl/SRPTrustManager.java new file mode 100644 index 000000000..664fa4cab --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/SRPTrustManager.java @@ -0,0 +1,99 @@ +/* SRPTrustManager.java -- interface to SRP trust managers. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl; + +import gnu.javax.crypto.sasl.srp.PasswordFile; + +import java.math.BigInteger; +import java.security.KeyPair; +import javax.net.ssl.TrustManager; + +/** + * A trust manager for secure remote password (SRP) key exchange cipher + * suites. This is a read-only interface to the {@link + * gnu.crypto.sasl.srp.PasswordFile} class, with convenience methods to + * generate session key pairs. + */ +public interface SRPTrustManager extends TrustManager +{ + + // Methods. + // ------------------------------------------------------------------------- + + /** + * Tests if the configured password file contains the specified user name. + * + * @param user The user name. + * @return True if the password file has an entry for user + */ + boolean contains(String user); + + /** + * Create and return a session SRP key pair for the given user name. + * + * @param user The user name to generate the key pair for. + * @return The session key pair, or null if there is no + * entry for user. + */ + KeyPair getKeyPair(String user); + + /** + * Returns the salt value for the given user. + * + * @param user The user name. + * @return The salt for user's entry, or null. + */ + byte[] getSalt(String user); + + /** + * Returns the password verifier for the given user. + * + * @param user The user name. + * @return user's password verifier, or null. + */ + BigInteger getVerifier(String user); + + /** + * Returns a reference to the SRP {@link PasswordFile} used by this + * {@link TrustManager}. + * + * @return a reference to the SRP password file in use. + */ + PasswordFile getPasswordFile(); +} diff --git a/libjava/classpath/gnu/javax/net/ssl/SSLCipherSuite.java b/libjava/classpath/gnu/javax/net/ssl/SSLCipherSuite.java new file mode 100644 index 000000000..80068e5cb --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/SSLProtocolVersion.java b/libjava/classpath/gnu/javax/net/ssl/SSLProtocolVersion.java new file mode 100644 index 000000000..3998f936a --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/SSLRecordHandler.java b/libjava/classpath/gnu/javax/net/ssl/SSLRecordHandler.java new file mode 100644 index 000000000..8a44245ce --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/SSLRecordHandler.java @@ -0,0 +1,100 @@ +/* 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.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; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/Session.java b/libjava/classpath/gnu/javax/net/ssl/Session.java new file mode 100644 index 000000000..3acf9932d --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/Session.java @@ -0,0 +1,366 @@ +/* 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 gnu.java.lang.CPStringBuilder; + +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() + { + CPStringBuilder str = new CPStringBuilder (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 (); + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/SessionStoreException.java b/libjava/classpath/gnu/javax/net/ssl/SessionStoreException.java new file mode 100644 index 000000000..4d8ef97d0 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/StaticTrustAnchors.java b/libjava/classpath/gnu/javax/net/ssl/StaticTrustAnchors.java new file mode 100644 index 000000000..480f1c754 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/StaticTrustAnchors.java @@ -0,0 +1,1940 @@ +/* StaticTrustAnchors.java -- static list of CA certificates. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl; + +import java.io.ByteArrayInputStream; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +import java.util.LinkedList; + +import javax.net.ssl.ManagerFactoryParameters; + +/** + * This class implements a simple set of trust anchors suitable for + * initializing a TrustManagerFactory for the "JessieX509" algorithm. + * + *

The important field of this class is the {@link #CA_CERTS} + * constant, which contains an array of commonly accepted CA + * certificates. + */ +public class StaticTrustAnchors implements ManagerFactoryParameters +{ + + // Fields. + // ------------------------------------------------------------------------- + + private X509Certificate[] certs; + + // Constructor. + // ------------------------------------------------------------------------- + + public StaticTrustAnchors(X509Certificate[] certs) + { + this.certs = (X509Certificate[]) certs.clone(); + } + + // Class method. + // ------------------------------------------------------------------------- + + public static X509Certificate generate(CertificateFactory factory, + String encoded) + { + try + { + ByteArrayInputStream in = + new ByteArrayInputStream(encoded.getBytes("UTF-8")); + return (X509Certificate) factory.generateCertificate(in); + } + catch (Exception x) + { + return null; + } + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public X509Certificate[] getCertificates() + { + return (X509Certificate[]) certs.clone(); + } + + // Constant. + // ------------------------------------------------------------------------- + + /** + * A list of known certificate authority certificates. This set of + * certificates is the same as the default CA certificates used by + * Mozilla. + */ + public static final StaticTrustAnchors CA_CERTS; + + // Static initializer. + // ------------------------------------------------------------------------- + + static + { + LinkedList certs = new LinkedList(); + CertificateFactory factory = null; + + try + { + factory = CertificateFactory.getInstance("X.509"); + } + catch (CertificateException ce) + { + throw new Error(ce.toString()); + } + + X509Certificate cert = generate(factory, + // ABAecom_=sub.__Am._Bankers_Assn.=_Root_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDtTCCAp2gAwIBAgIRANAeQJAAAEZSAAAAAQAAAAQwDQYJKoZIhvcNAQEF\n" + + "BQAwgYkxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJEQzETMBEGA1UEBxMKV2Fz\n" + + "aGluZ3RvbjEXMBUGA1UEChMOQUJBLkVDT00sIElOQy4xGTAXBgNVBAMTEEFC\n" + + "QS5FQ09NIFJvb3QgQ0ExJDAiBgkqhkiG9w0BCQEWFWFkbWluQGRpZ3NpZ3Ry\n" + + "dXN0LmNvbTAeFw05OTA3MTIxNzMzNTNaFw0wOTA3MDkxNzMzNTNaMIGJMQsw\n" + + "CQYDVQQGEwJVUzELMAkGA1UECBMCREMxEzARBgNVBAcTCldhc2hpbmd0b24x\n" + + "FzAVBgNVBAoTDkFCQS5FQ09NLCBJTkMuMRkwFwYDVQQDExBBQkEuRUNPTSBS\n" + + "b290IENBMSQwIgYJKoZIhvcNAQkBFhVhZG1pbkBkaWdzaWd0cnVzdC5jb20w\n" + + "ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx0xHgeVVDBwhMywVC\n" + + "AOINg0Y95JO6tgbTDVm9PsHOQ2cBiiGo77zM0KLMsFWWU4RmBQDaREmA2FQK\n" + + "pSWGlO1jVv9wbKOhGdJ4vmgqRF4vz8wYXke8OrFGPR7wuSw0X4x8TAgpnUBV\n" + + "6zx9g9618PeKgw6hTLQ6pbNfWiKX7BmbwQVo/ea3qZGULOR4SCQaJRk665Wc\n" + + "OQqKz0Ky8BzVX/tr7WhWezkscjiw7pOp03t3POtxA6k4ShZsiSrK2jMTecJV\n" + + "jO2cu/LLWxD4LmE1xilMKtAqY9FlWbT4zfn0AIS2V0KFnTKo+SpU+/94Qby9\n" + + "cSj0u5C8/5Y0BONFnqFGKECBAgMBAAGjFjAUMBIGA1UdEwEB/wQIMAYBAf8C\n" + + "AQgwDQYJKoZIhvcNAQEFBQADggEBAARvJYbk5pYntNlCwNDJALF/VD6Hsm0k\n" + + "qS8Kfv2kRLD4VAe9G52dyntQJHsRW0mjpr8SdNWJt7cvmGQlFLdh6X9ggGvT\n" + + "ZOirvRrWUfrAtF13Gn9kCF55xgVM8XrdTX3O5kh7VNJhkoHWG9YA8A6eKHeg\n" + + "TYjHInYZw8eeG6Z3ePhfm1bR8PIXrI6dWeYf/le22V7hXZ9F7GFoGUHhsiAm\n" + + "/lowdiT/QHI8eZ98IkirRs3bs4Ysj78FQdPB4xTjQRcm0HyncUwZ6EoPclgx\n" + + "fexgeqMiKL0ZJGA/O4dzwGvky663qyVDslUte6sGDnVdNOVdc22esnVApVnJ\n" + + "TzFxiNmIf1Q=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // AOL_Time_Warner_Root_Certification_Authority_1.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIID5jCCAs6gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMC\n" + + "VVMxHTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNB\n" + + "bWVyaWNhIE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIg\n" + + "Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyOTA2MDAw\n" + + "MFoXDTM3MTEyMDE1MDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRB\n" + + "T0wgVGltZSBXYXJuZXIgSW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUg\n" + + "SW5jLjE3MDUGA1UEAxMuQU9MIFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNh\n" + + "dGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n" + + "ggEBAJnej8Mlo2k06AX3dLm/WpcZuS+U0pPlLYnKhHw/EEMbjIt8hFj4JHxI\n" + + "zyr9wBXZGH6EGhfT257XyuTZ16pYUYfw8ItITuLCxFlpMGK2MKKMCxGZYTVt\n" + + "fu/FsRkGIBKOQuHfD5YQUqjPnF+VFNivO3ULMSAfRC+iYkGzuxgh28pxPIzs\n" + + "trkNn+9R7017EvILDOGsQI93f7DKeHEMXRZxcKLXwjqFzQ6axOAAsNUl6twr\n" + + "5JQtOJyJQVdkKGUZHLZEtMgxa44Be3ZZJX8VHIQIfHNlIAqhBC4aMqiaILGc\n" + + "LCFZ5/vP7nAtCMpjPiybkxlqpMKX/7eGV4iFbJ4VFitNLLMCAwEAAaNjMGEw\n" + + "DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUoTYwFsuGkABFgFOxj8jYPXy+\n" + + "XxIwHwYDVR0jBBgwFoAUoTYwFsuGkABFgFOxj8jYPXy+XxIwDgYDVR0PAQH/\n" + + "BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQCKIBilvrMvtKaEAEAwKfq0FHNM\n" + + "eUWn9nDg6H5kHgqVfGphwu9OH77/yZkfB2FK4V1Mza3u0FIy2VkyvNp5ctZ7\n" + + "CegCgTXTCt8RHcl5oIBN/lrXVtbtDyqvpxh1MwzqwWEFT2qaifKNuZ8u77Bf\n" + + "WgDrvq2g+EQFZ7zLBO+eZMXpyD8Fv8YvBxzDNnGGyjhmSs3WuEvGbKeXO/oT\n" + + "LW4jYYehY0KswsuXn2Fozy1MBJ3XJU8KDk2QixhWqJNIV9xvrr2eZ1d3iVCz\n" + + "vhGbRWeDhhmH05i9CBoWH1iCC+GWaQVLjuyDUTEH1dSf/1l7qG6Fz9NLqUmw\n" + + "X7A5KGgOc90lmt4S\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // AOL_Time_Warner_Root_Certification_Authority_2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIF5jCCA86gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMC\n" + + "VVMxHTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNB\n" + + "bWVyaWNhIE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIg\n" + + "Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyOTA2MDAw\n" + + "MFoXDTM3MDkyODIzNDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRB\n" + + "T0wgVGltZSBXYXJuZXIgSW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUg\n" + + "SW5jLjE3MDUGA1UEAxMuQU9MIFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNh\n" + + "dGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC\n" + + "ggIBALQ3WggWmRToVbEbJGv8x4vmh6mJ7ouZzU9AhqS2TcnZsdw8TQ2FTBVs\n" + + "RotSeJ/4I/1n9SQ6aF3Q92RhQVSji6UI0ilbm2BPJoPRYxJWSXakFsKlnUWs\n" + + "i4SVqBax7J/qJBrvuVdcmiQhLE0OcR+mrF1FdAOYxFSMFkpBd4aVdQxHAWZg\n" + + "/BXxD+r1FHjHDtdugRxev17nOirYlxcwfACtCJ0zr7iZYYCLqJV+FNwSbKTQ\n" + + "2O9ASQI2+W6p1h2WVgSysy0WVoaP2SBXgM1nEG2wTPDaRrbqJS5Gr42whTg0\n" + + "ixQmgiusrpkLjhTXUr2eacOGAgvqdnUxCc4zGSGFQ+aJLZ8lN2fxI2rSAG2X\n" + + "+Z/nKcrdH9cG6rjJuQkhn8g/BsXS6RJGAE57COtCPStIbp1n3UsC5ETzkxml\n" + + "J85per5n0/xQpCyrw2u544BMzwVhSyvcG7mm0tCq9Stz+86QNZ8MUhy/XCFh\n" + + "EVsVS6kkUfykXPcXnbDS+gfpj1bkGoxoigTTfFrjnqKhynFbotSg5ymFXQNo\n" + + "Kk/SBtc9+cMDLz9l+WceR0DTYw/j1Y75hauXTLPXJuuWCpTehTacyH+BCQJJ\n" + + "Kg71ZDIMgtG6aoIbs0t0EfOMd9afv9w3pKdVBC/UMejTRrkDfNoSTllkt1Ex\n" + + "MVCgyhwn2RAurda9EGYrw7AiShJbAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMB\n" + + "Af8wHQYDVR0OBBYEFE9pbQN+nZ8HGEO8txBO1b+pxCAoMB8GA1UdIwQYMBaA\n" + + "FE9pbQN+nZ8HGEO8txBO1b+pxCAoMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG\n" + + "9w0BAQUFAAOCAgEAO/Ouyuguh4X7ZVnnrREUpVe8WJ8kEle7+z802u6teio0\n" + + "cnAxa8cZmIDJgt43d15Ui47y6mdPyXSEkVYJ1eV6moG2gcKtNuTxVBFT8zRF\n" + + "ASbI5Rq8NEQh3q0l/HYWdyGQgJhXnU7q7C+qPBR7V8F+GBRn7iTGvboVsNIY\n" + + "vbdVgaxTwOjdaRITQrcCtQVBynlQboIOcXKTRuidDV29rs4prWPVVRaAMCf/\n" + + "drr3uNZK49m1+VLQTkCpx+XCMseqdiThawVQ68W/ClTluUI8JPu3B5wwn3la\n" + + "5uBAUhX0/Kr0VvlEl4ftDmVyXr4m+02kLQgH3thcoNyBM5kYJRF3p+v9WAks\n" + + "mWsbivNSPxpNSGDxoPYzAlOL7SUJuA0t7Zdz7NeWH45gDtoQmy8YJPamTQr5\n" + + "O8t1wswvziRpyQoijlmn94IM19drNZxDAGrElWe6nEXLuA4399xOAU++CrYD\n" + + "062KRffaJ00psUjf5BHklka9bAI+1lHIlRcBFanyqqryvy9lG2/QuRqT9Y41\n" + + "xICHPpQvZuTpqP9BnHAqTyo5GJUefvthATxRCC4oGKQWDzH9OmwjkyB24f0H\n" + + "hdFbP9IcczLd+rn4jM8Ch3qaluTtT4mNU0OrDhPAARW0eTjb/G49nlG2uBOL\n" + + "Z8/5fNkiHfZdxRwBL5joeiQYvITX+txyW/fBOmg=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // AddTrust_External_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJT\n" + + "RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4\n" + + "dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5h\n" + + "bCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzEL\n" + + "MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1B\n" + + "ZGRUcnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1\n" + + "c3QgRXh0ZXJuYWwgQ0EgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\n" + + "AQoCggEBALf3GjPm8gAELTngTlvtH7xsD821+iO2zt6bETOXpClMfZOfvUq8\n" + + "k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfwTz/oMp50\n" + + "ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504\n" + + "B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDez\n" + + "eWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5\n" + + "aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0WicCAwEAAaOB\n" + + "3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0PBAQD\n" + + "AgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6\n" + + "xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU\n" + + "cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdv\n" + + "cmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJ\n" + + "KoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl\n" + + "j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5R\n" + + "xNKWt9x+Tu5w/Rw56wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjT\n" + + "K3rMUUKhemPR5ruhxSvCNr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1\n" + + "n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHx\n" + + "REzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49O\n" + + "hgQ=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // AddTrust_Low-Value_Services_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJT\n" + + "RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU\n" + + "UCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3Qw\n" + + "HhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJT\n" + + "RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU\n" + + "UCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3Qw\n" + + "ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwze\n" + + "xODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY654eyNAbFvAWlA3yCyykQruGI\n" + + "gb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWroulpOj0O\n" + + "M3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1Lc\n" + + "sRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5\n" + + "mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG\n" + + "9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0OBBYEFJWxtPCU\n" + + "tr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTADAQH/\n" + + "MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQsw\n" + + "CQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk\n" + + "ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAx\n" + + "IENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0\n" + + "MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0Ph\n" + + "iVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9\n" + + "tTEv2dB8Xfjea4MYeDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL\n" + + "/bscVjby/rK25Xa71SJlpz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlV\n" + + "g3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6\n" + + "tkD9xOQ14R0WHNC8K47Wcdk=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // AddTrust_Public_Services_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJT\n" + + "RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU\n" + + "UCBOZXR3b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAe\n" + + "Fw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNF\n" + + "MRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQ\n" + + "IE5ldHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIB\n" + + "IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+\n" + + "A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c\n" + + "+OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1id9NEHif2\n" + + "P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKX\n" + + "C1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8R\n" + + "s3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9\n" + + "BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQWBBSBPjfYkrAf\n" + + "d59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zCB\n" + + "jgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkG\n" + + "A1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU\n" + + "cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENB\n" + + "IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmu\n" + + "G7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL\n" + + "+YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbj\n" + + "PGsye/Kf8Lb93/AoGEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bY\n" + + "GozH7ZxOmuASu7VqTITh4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6\n" + + "NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9HEufOX1362Kqx\n" + + "My3ZdvJOOjMMK7MtkAY=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // AddTrust_Qualified_Certificates_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJT\n" + + "RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU\n" + + "UCBOZXR3b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9v\n" + + "dDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYT\n" + + "AlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3Qg\n" + + "VFRQIE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBS\n" + + "b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoek\n" + + "n0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKk\n" + + "IhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3KP0q6p6z\n" + + "sLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1t\n" + + "UvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R\n" + + "+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvES\n" + + "a0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0GA1UdDgQWBBQ5\n" + + "lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw\n" + + "AwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkw\n" + + "ZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL\n" + + "ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVh\n" + + "bGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2Vh\n" + + "lRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxG\n" + + "GuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx9\n" + + "5dr6h+sNNVJn0J6XdgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKF\n" + + "Yqa0p9m9N5xotS1WfbC3P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVA\n" + + "wRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQw\n" + + "dOUeqN48Jzd/g66ed8/wMLH/S5noxqE=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // America_Online_Root_Certification_Authority_1.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJV\n" + + "UzEcMBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1l\n" + + "cmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4X\n" + + "DTAyMDUyODA2MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkGA1UEBhMCVVMx\n" + + "HDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJp\n" + + "Y2EgT25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIw\n" + + "DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCa\n" + + "xlCyfqXfaE0bfA+2l2h9LaaLl+lkhsmj76CGv2BlnEtUiMJIxUo5vxTjWVXl\n" + + "GbR0yLQFOVwWpeKVBeASrlmLojNoWBym1BW32J/X3HGrfpq/m44zDyL9Hy7n\n" + + "BzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsWOqMFf6Dch9Wc/HKpoH145Lcx\n" + + "VR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb2xzTa5qGUwew76wGePiE\n" + + "mf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQkoO3rHl+Ee5fSfwMCu\n" + + "JKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAdBgNV\n" + + "HQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAUAK3Zo/Z5\n" + + "9m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUA\n" + + "A4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkF\n" + + "Zu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B6UlwGBaXCBOM\n" + + "IOAbLjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTI\n" + + "dGcL+oiroQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43g\n" + + "Kd8hdIaC2y+CMMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j\n" + + "8uB9Gr784N/Xx6dssPmuujz9dLQR6FgNgLzTqIA6me11zEZ7\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // America_Online_Root_Certification_Authority_2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJV\n" + + "UzEcMBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1l\n" + + "cmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4X\n" + + "DTAyMDUyODA2MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkGA1UEBhMCVVMx\n" + + "HDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJp\n" + + "Y2EgT25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIw\n" + + "DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssN\n" + + "t79Hc9PwVU3dxgz6sWYFas14tNwC206B89enfHG8dWOgXeMHDEjsJcQDIPT/\n" + + "DjsS/5uN4cbVG7RtIuOx238hZK+GvFciKtZHgVdEglZTvYYUAQv8f3SkWq7x\n" + + "uhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2JxhP7JsowtS013wMPgwr38oE\n" + + "18aO6lhOqKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9BoInLRBYBbV4Bbkv2wxr\n" + + "kJB+FFk4u5QkE+XRnRTf04JNRvCAOVIyD+OEsnpD8l7eXz8d3eOyG6ChKiMD\n" + + "bi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0gBe4lL8BPeraunzgWGcX\n" + + "uVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67Xnfn6KVu\n" + + "Y8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEqZ8A9\n" + + "W6Wa6897GqidFEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZ\n" + + "o2C7HK2JNDJiuEMhBnIMoVxtRsX6Kc8w3onccVvdtjc+31D1uAclJuW8tf48\n" + + "ArO3+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnjB453cMor9H124Hhn\n" + + "AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3Op\n" + + "aaEg5+31IqEjFNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNee\n" + + "MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypL\n" + + "M7PmG2tZTiLMubekJcmnxPBUlgtk87FYT15R/LKXeydlwuXK5w0MJXti4/qf\n" + + "tIe3RUavg6WXSIylvfEWK5t2LHo1YGwRgJfMqZJS5ivmae2p+DYtLHe/YUjR\n" + + "Ywu5W1LtGLBDQiKmsXeu3mnFzcccobGlHBD7GL4acN3Bkku+KVqdPzW+5X1R\n" + + "+FXgJXUjhx5c3LqdsKyzadsXg8n33gy8CNyRnqjQ1xU3c6U1uPx+xURABsPr\n" + + "+CKAXEfOAuMRn0T//ZoyzH1kUQ7rVyZ2OuMeIjzCpjbdGe+n/BLzJsBZMYVM\n" + + "nNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgOZtMADjMSW7yV5TKQqLPGbIOt\n" + + "d+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2FAjgQ5ANh1NolNscI\n" + + "WC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUXOm/9riW99XJZ\n" + + "ZLF0KjhfGEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPbAZO1XB4Y\n" + + "3WRayhgoPmMEEf0cjQAPuDffZ4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQlZvqz\n" + + "2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuPcX/9XhmgD0uRuMRUvAaw\n" + + "RY8mkaKO/qk=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Baltimore_CyberTrust_Code_Signing_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDpjCCAo6gAwIBAgIEAgAAvzANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQG\n" + + "EwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0\n" + + "MS8wLQYDVQQDEyZCYWx0aW1vcmUgQ3liZXJUcnVzdCBDb2RlIFNpZ25pbmcg\n" + + "Um9vdDAeFw0wMDA1MTcxNDAxMDBaFw0yNTA1MTcyMzU5MDBaMGcxCzAJBgNV\n" + + "BAYTAklFMRIwEAYDVQQKEwlCYWx0aW1vcmUxEzARBgNVBAsTCkN5YmVyVHJ1\n" + + "c3QxLzAtBgNVBAMTJkJhbHRpbW9yZSBDeWJlclRydXN0IENvZGUgU2lnbmlu\n" + + "ZyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyHGaGBKO\n" + + "etv5mvxBr9jy9AmOrT/+Zzc82skmULGxPsvoTnMA8rLc88VG+wnvGJbOp+Cc\n" + + "hF0gDnqgqjaL+ii2eC6z7OhH8wTwkCO06q/lU7gF90ddK4bxp6TGOzW20g1S\n" + + "Qdf0knXhogpQVoe+lwt7M4UQuSgY7jPqSBHXW5FHdiLU7s9d56hOHJ2Wkd2c\n" + + "vXQJqHJhqrAhOvE9LANWCdLB3MO1x1Q3q+YmorJGcXPKEYjuvOdk99ARGnNA\n" + + "WshJLA+375B/aIAEOAsbDzvU9aCzwo7hNLSAmW2edtSSKUCxldI3pGcSf+Bi\n" + + "u641xZk2gkS45ngYM2Fxk1stjZ94lYLrbQIDAQABo1owWDATBgNVHSUEDDAK\n" + + "BggrBgEFBQcDAzAdBgNVHQ4EFgQUyEE0XBUVBOVA8tGrmm8kknqHQlowEgYD\n" + + "VR0TAQH/BAgwBgEB/wIBAzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEF\n" + + "BQADggEBAFJ0qpVLIozHPZak/l36L7W86/AL6VY4HdFtDaG8aIvwxYClJDT9\n" + + "8pYYEYahNvU351RA1WQfw19wQmstOceeUgXO52py0o1yP0dQg6vHjSXJsOOn\n" + + "UxaVpmpT6hidj3ipd3ca+bSXR1mIJyi1yuEu1z4Oog24IkQD49FjsEE6ofWk\n" + + "Lfd2HgRUmXgyQNcrfE26ppyweW4Hvozs7tc4aVvBDFZon/7r0eHIiPnyzX++\n" + + "hbREZwBQPvQmA2Tqd33oXj4cN0fI1uqk8zY8l8I5cgWUGSXD1zdBD8Efh4r9\n" + + "qr7psWRX5NuSoc/hSeg7H5ETWsOP2SVYSYBHD8YDrqzjv7fAqio=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Baltimore_CyberTrust_Mobile_Commerce_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICfTCCAeagAwIBAgIEAgAAuDANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG\n" + + "EwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0\n" + + "MSkwJwYDVQQDEyBCYWx0aW1vcmUgQ3liZXJUcnVzdCBNb2JpbGUgUm9vdDAe\n" + + "Fw0wMDA1MTIxODIwMDBaFw0yMDA1MTIyMzU5MDBaMGExCzAJBgNVBAYTAklF\n" + + "MRIwEAYDVQQKEwlCYWx0aW1vcmUxEzARBgNVBAsTCkN5YmVyVHJ1c3QxKTAn\n" + + "BgNVBAMTIEJhbHRpbW9yZSBDeWJlclRydXN0IE1vYmlsZSBSb290MIGfMA0G\n" + + "CSqGSIb3DQEBAQUAA4GNADCBiQKBgQCjbbE4Vqz8tVYh3sCQXSZHgsZ9jx+g\n" + + "hY8vu9ThHB3yJB8osC+5pKVvoiIgZP6ERzx+K2xparjUwJaOjFINzW9B1L8E\n" + + "rqeBLy2YSNLBlKO1GV1dUWT0jkGwm8AtIqBexthaEmO8EUpeJhId4iYF5g9f\n" + + "Ih96X3aUrs9aKA6rRdoiMQIDAQABo0IwQDAdBgNVHQ4EFgQUyeKPwAImWrbA\n" + + "B+N/lAcY2y6lmnAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYw\n" + + "DQYJKoZIhvcNAQEFBQADgYEAUwgLJgl4QnPU7Hp3Rw3jCzNx764zFE37+v0a\n" + + "t1H15JkcBnHXKRnX5hUgUVFGbU/eGEmY0Ph4u3HojQEG1ddkj5TfR/6ghWk2\n" + + "qS9CemhKEtaLC3BECqQE7yaIwTVxOF0bW0hC8OeUHHCVNKir9avieK318FL9\n" + + "m+pCDOjYVL5TZvU=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Baltimore_CyberTrust_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQG\n" + + "EwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0\n" + + "MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUx\n" + + "MjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNV\n" + + "BAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZ\n" + + "QmFsdGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQAD\n" + + "ggEPADCCAQoCggEBAKMEuyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+h\n" + + "Xe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gR\n" + + "QKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/CG9VwcPCP\n" + + "wBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1\n" + + "pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNT\n" + + "Px8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkC\n" + + "AwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1BE3wMBIGA1Ud\n" + + "EwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUA\n" + + "A4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkT\n" + + "I7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx\n" + + "jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/\n" + + "oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67\n" + + "G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H\n" + + "RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Digital_Signature_Trust_Co._Global_CA_1.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQG\n" + + "EwJVUzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREw\n" + + "DwYDVQQLEwhEU1RDQSBFMTAeFw05ODEyMTAxODEwMjNaFw0xODEyMTAxODQw\n" + + "MjNaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVy\n" + + "ZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEB\n" + + "AQUAA4GLADCBhwKBgQCgbIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlR\n" + + "EmlvMVW5SXIACH7TpWJENySZj9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+Lth\n" + + "zfNHwJmm8fOR6Hh8AMthyUQncWlVSn5JTe2io74CTADKAqjuAQIxZA9SLRN0\n" + + "dja1erQtcQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBoBgNVHR8E\n" + + "YTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwg\n" + + "U2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTExDTALBgNV\n" + + "BAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMTAxODEwMjNagQ8yMDE4MTIx\n" + + "MDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFGp5fpFpRhgTCgJ3\n" + + "pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i+DAMBgNV\n" + + "HRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3\n" + + "DQEBBQUAA4GBACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lN\n" + + "QseSJqBcNJo4cvj9axY+IO6CizEqkzaFI4iKPANo08kJD038bKTaKHKTDomA\n" + + "sH3+gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4RbyhkwS7hp86W0N6\n" + + "w4pl\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Digital_Signature_Trust_Co._Global_CA_2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIID2DCCAsACEQDQHkCLAAACfAAAAAIAAAABMA0GCSqGSIb3DQEBBQUAMIGp\n" + + "MQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBM\n" + + "YWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENv\n" + + "LjERMA8GA1UECxMIRFNUQ0EgWDExFjAUBgNVBAMTDURTVCBSb290Q0EgWDEx\n" + + "ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODEyMDEx\n" + + "ODE4NTVaFw0wODExMjgxODE4NTVaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UE\n" + + "CBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0Rp\n" + + "Z2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgWDEx\n" + + "FjAUBgNVBAMTDURTVCBSb290Q0EgWDExITAfBgkqhkiG9w0BCQEWEmNhQGRp\n" + + "Z3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n" + + "ANLGJrbnpT3BxGjVUG9TxW9JEwm4ryxIjRRqoxdfWvnTLnUv2Chi0ZMv/E3U\n" + + "q4flCMeZ55I/db3rJbQVwZsZPdJEjdd0IG03Ao9pk1uKxBmd9LIO/BZsubEF\n" + + "koPRhSxglD5FVaDZqwgh5mDoO3TymVBRaNADLbGAvqPYUrBEzUNKcI5YhZXh\n" + + "TizWLUFv1oTnyJhEykfbLCSlaSbPa7gnYsP0yXqSI+0TZ4KuRS5F5X5yP4Wd\n" + + "lGIQ5jyRoa13AOAV7POEgHJ6jm5gl8ckWRA0g1vhpaRptlc1HHhZxtMvOnNn\n" + + "7pTKBBMFYgZwI7P0fO5F2WQLW0mqpEPOJsREEmy43XkCAwEAATANBgkqhkiG\n" + + "9w0BAQUFAAOCAQEAojeyP2n714Z5VEkxlTMr89EJFEliYIalsBHiUMIdBlc+\n" + + "LegzZL6bqq1fG03UmZWii5rJYnK1aerZWKs17RWiQ9a2vAd5ZWRzfdd5ynvV\n" + + "WlHG4VMElo04z6MXrDlxawHDi1M8Y+nuecDkvpIyZHqzH5eUYr3qsiAVlfuX\n" + + "8ngvYzZAOONGDx3drJXK50uQe7FLqdTF65raqtWjlBRGjS0f8zrWkzr2Pnn8\n" + + "6Oawde3uPclwx12qgUtGJRzHbBXjlU4PqjI3lAoXJJIThFjSY28r9+ZbYgsT\n" + + "F7ANUkz+/m9c4pFuHf2kYtdo+o56T9II2pPc8JIRetDccpMMc5NihWjQ9A==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Digital_Signature_Trust_Co._Global_CA_3.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQG\n" + + "EwJVUzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREw\n" + + "DwYDVQQLEwhEU1RDQSBFMjAeFw05ODEyMDkxOTE3MjZaFw0xODEyMDkxOTQ3\n" + + "MjZaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVy\n" + + "ZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEB\n" + + "AQUAA4GLADCBhwKBgQC/k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fB\n" + + "w18DW9Fvrn5C6mYjuGODVvsoLeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87e\n" + + "ZfCocfdPJmyMvMa1795JJ/9IKn3oTQPMx7JSxhcxEzu1TdvIxPbDDyQq2gyd\n" + + "55FbgM2UnQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBoBgNVHR8E\n" + + "YTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwg\n" + + "U2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTIxDTALBgNV\n" + + "BAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMDkxOTE3MjZagQ8yMDE4MTIw\n" + + "OTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFB6CTShlgDzJQW6s\n" + + "NS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5WzAMBgNV\n" + + "HRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3\n" + + "DQEBBQUAA4GBAEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHR\n" + + "xdf0CiUPPXiBng+xZ8SQTGPdXqfiup/1902lMXucKS1M/mQ+7LZT/uqb7YLb\n" + + "dHVLB3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1mPnHfxsb1gYgAlih\n" + + "w6ID\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Digital_Signature_Trust_Co._Global_CA_4.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIID2DCCAsACEQDQHkCLAAB3bQAAAAEAAAAEMA0GCSqGSIb3DQEBBQUAMIGp\n" + + "MQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBM\n" + + "YWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENv\n" + + "LjERMA8GA1UECxMIRFNUQ0EgWDIxFjAUBgNVBAMTDURTVCBSb290Q0EgWDIx\n" + + "ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODExMzAy\n" + + "MjQ2MTZaFw0wODExMjcyMjQ2MTZaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UE\n" + + "CBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0Rp\n" + + "Z2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgWDIx\n" + + "FjAUBgNVBAMTDURTVCBSb290Q0EgWDIxITAfBgkqhkiG9w0BCQEWEmNhQGRp\n" + + "Z3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n" + + "ANx18IzAdZaawGIfJvfE4Zrq4FZzW5nNAUSoCLbVp9oaBBg5kkp4o4HC9Xd6\n" + + "ULRw/5qrxsfKboNPQpj7Jgva3G3WqZlVUmfpKAOS3OWwBZoPFflrWXJW8vo5\n" + + "/Kpo7g8fEIMv/J36F5bdguPmRX3AS4BEH+0s4IT9kVySVGkl5WJp3OXuAFK9\n" + + "MwutdQKFp2RQLcUZGTDAJtvJ0/0uma1ZtQtN1EGuhUhDWdy3qOKi3sOP17ih\n" + + "YqZoUFLkzzGnlIXan0YyF1bl8utmPRL/Q9uY73fPy4GNNLHGUEom0eQ+QVCv\n" + + "bK4iNC7Va26Dunm4dmVI2gkpZGMiuftHdoWMhkTLCdsCAwEAATANBgkqhkiG\n" + + "9w0BAQUFAAOCAQEAtTYOXeFhKFoRZcA/gwN5Tb4opgsHAlKFzfiR0BBstWog\n" + + "WxyQ2TA8xkieil5k+aFxd+8EJx8H6+Qm93N0yUQYGmbT4EOvkTvRyyzYdFQ6\n" + + "HE3K1GjNI3wdEJ5F6fYAbqbNGf9PLCmPV03Ed5K+4EwJ+11EhmYhqLkyolbV\n" + + "6YyDfFk/xPEL553snr2cGA4+wjl5KLcDDQjLxufZATdQEOzMYRZA1K8xdHv8\n" + + "PzGn0EdzMzkbzE5q10mDEQb+64JYMzJM8FasHpwvVpp7wUocpf1VNs78lk30\n" + + "sPDst2yC7S8xmUJMqbINuBVd8d+6ybVK1GSYsyapMMj9puyrliGtf8J4tg==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Entrust.net_Global_Secure_Personal_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEgzCCA+ygAwIBAgIEOJ725DANBgkqhkiG9w0BAQQFADCBtDEUMBIGA1UE\n" + + "ChMLRW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9HQ0NB\n" + + "X0NQUyBpbmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsT\n" + + "HChjKSAyMDAwIEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1\n" + + "c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMDAy\n" + + "MDcxNjE2NDBaFw0yMDAyMDcxNjQ2NDBaMIG0MRQwEgYDVQQKEwtFbnRydXN0\n" + + "Lm5ldDFAMD4GA1UECxQ3d3d3LmVudHJ1c3QubmV0L0dDQ0FfQ1BTIGluY29y\n" + + "cC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDIwMDAg\n" + + "RW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xp\n" + + "ZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA\n" + + "A4GNADCBiQKBgQCTdLS25MVL1qFof2LV7PdRV7NySpj10InJrWPNTTVRaoTU\n" + + "rcloeW+46xHbh65cJFET8VQlhK8pK5/jgOLZy93GRUk0iJBeAZfv6lOm3fzB\n" + + "3ksqJeTpNfpVBQbliXrqpBFXO/x8PTbNZzVtpKklWb1m9fkn5JVn1j+SgF7y\n" + + "NH0rhQIDAQABo4IBnjCCAZowEQYJYIZIAYb4QgEBBAQDAgAHMIHdBgNVHR8E\n" + + "gdUwgdIwgc+ggcyggcmkgcYwgcMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUAw\n" + + "PgYDVQQLFDd3d3cuZW50cnVzdC5uZXQvR0NDQV9DUFMgaW5jb3JwLiBieSBy\n" + + "ZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMjAwMCBFbnRydXN0\n" + + "Lm5ldCBMaW1pdGVkMTMwMQYDVQQDEypFbnRydXN0Lm5ldCBDbGllbnQgQ2Vy\n" + + "dGlmaWNhdGlvbiBBdXRob3JpdHkxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQw\n" + + "IoAPMjAwMDAyMDcxNjE2NDBagQ8yMDIwMDIwNzE2NDY0MFowCwYDVR0PBAQD\n" + + "AgEGMB8GA1UdIwQYMBaAFISLdP3FjcD/J20gN0V8/i3OutN9MB0GA1UdDgQW\n" + + "BBSEi3T9xY3A/ydtIDdFfP4tzrrTfTAMBgNVHRMEBTADAQH/MB0GCSqGSIb2\n" + + "fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQQFAAOBgQBObzWA\n" + + "O9GK9Q6nIMstZVXQkvTnhLUGJoMShAusO7JE7r3PQNsgDrpuFOow4DtifH+L\n" + + "a3xKp9U1PL6oXOpLu5OOgGarDyn9TS2/GpsKkMWr2tGzhtQvJFJcem3G8v7l\n" + + "TRowjJDyutdKPkN+1MhQGof4T4HHdguEOnKdzmVml64mXg==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Entrust.net_Global_Secure_Server_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIElTCCA/6gAwIBAgIEOJsRPDANBgkqhkiG9w0BAQQFADCBujEUMBIGA1UE\n" + + "ChMLRW50cnVzdC5uZXQxPzA9BgNVBAsUNnd3dy5lbnRydXN0Lm5ldC9TU0xf\n" + + "Q1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc\n" + + "KGMpIDIwMDAgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVz\n" + + "dC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe\n" + + "Fw0wMDAyMDQxNzIwMDBaFw0yMDAyMDQxNzUwMDBaMIG6MRQwEgYDVQQKEwtF\n" + + "bnRydXN0Lm5ldDE/MD0GA1UECxQ2d3d3LmVudHJ1c3QubmV0L1NTTF9DUFMg\n" + + "aW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykg\n" + + "MjAwMCBFbnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5l\n" + + "dCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0G\n" + + "CSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHwV9OcfHO8GCGD9JYf9Mzly0XonUw\n" + + "tZZkJi9ow0SrqHXmAGc0V55lxyKbc+bT3QgON1WqJUaBbL3+qPZ1V1eMkGxK\n" + + "wz6LS0MKyRFWmponIpnPVZ5h2QLifLZ8OAfc439PmrkDQYC2dWcTC5/oVzbI\n" + + "XQA23mYU2m52H083jIITiQIDAQABo4IBpDCCAaAwEQYJYIZIAYb4QgEBBAQD\n" + + "AgAHMIHjBgNVHR8EgdswgdgwgdWggdKggc+kgcwwgckxFDASBgNVBAoTC0Vu\n" + + "dHJ1c3QubmV0MT8wPQYDVQQLFDZ3d3cuZW50cnVzdC5uZXQvU1NMX0NQUyBp\n" + + "bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAy\n" + + "MDAwIEVudHJ1c3QubmV0IExpbWl0ZWQxOjA4BgNVBAMTMUVudHJ1c3QubmV0\n" + + "IFNlY3VyZSBTZXJ2ZXIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxDTALBgNV\n" + + "BAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMDAyMDQxNzIwMDBagQ8yMDIwMDIw\n" + + "NDE3NTAwMFowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFMtswGvjuz7L/CKc\n" + + "/vuLkpyw8m4iMB0GA1UdDgQWBBTLbMBr47s+y/winP77i5KcsPJuIjAMBgNV\n" + + "HRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkq\n" + + "hkiG9w0BAQQFAAOBgQBi24GRzsiad0Iv7L0no1MPUBvqTpLwqa+poLpIYcvv\n" + + "yQbvH9X07t9WLebKahlzqlO+krNQAraFJnJj2HVQYnUUt7NQGj/KEQALhUVp\n" + + "bbalrlHhStyCP2yMNLJ3a9kC9n8O6mUE8c1UyrrJzOCE98g+EZfTYAkYvAX/\n" + + "bIkz8OwVDw==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Entrust.net_Premium_2048_Secure_Server_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UE\n" + + "ChMLRW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNf\n" + + "MjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsT\n" + + "HChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1\n" + + "c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEy\n" + + "MjQxNzUwNTFaFw0xOTEyMjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0\n" + + "Lm5ldDFAMD4GA1UECxQ3d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29y\n" + + "cC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkg\n" + + "RW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2Vy\n" + + "dGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEF\n" + + "AAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4\n" + + "QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/EC\n" + + "DNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuXMlBvPci6Zgzj\n" + + "/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzWnLLP\n" + + "KQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZd\n" + + "enoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH\n" + + "4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB\n" + + "0RGAvtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJ\n" + + "FrlwMB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0B\n" + + "AQUFAAOCAQEAWUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFh\n" + + "fGPjK50xA3B20qMooPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVU\n" + + "KcgF7bISKo30Axv/55IQh7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaoho\n" + + "wXkCIryqptau37AUX7iH0N18f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2\n" + + "+z7pnIkPFc4YsIV4IU9rTw76NmfNB/L/CNDi3tm/Kq+4h4YhPATKt5Rof888\n" + + "6ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVyvUxFnmG6v4SBkgPR0ml8xQ==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Entrust.net_Secure_Personal_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIE7TCCBFagAwIBAgIEOAOR7jANBgkqhkiG9w0BAQQFADCByTELMAkGA1UE\n" + + "BhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUgwRgYDVQQLFD93d3cuZW50\n" + + "cnVzdC5uZXQvQ2xpZW50X0NBX0luZm8vQ1BTIGluY29ycC4gYnkgcmVmLiBs\n" + + "aW1pdHMgbGlhYi4xJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExp\n" + + "bWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0\n" + + "aW9uIEF1dGhvcml0eTAeFw05OTEwMTIxOTI0MzBaFw0xOTEwMTIxOTU0MzBa\n" + + "MIHJMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNV\n" + + "BAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5mby9DUFMgaW5jb3Jw\n" + + "LiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMpIDE5OTkgRW50\n" + + "cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xpZW50\n" + + "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GL\n" + + "ADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/Bo6oT9n3V5z8GKUZSv\n" + + "x1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux5zDeg7K6PvHV\n" + + "iTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zmAqTmT173\n" + + "iwIBA6OCAeAwggHcMBEGCWCGSAGG+EIBAQQEAwIABzCCASIGA1UdHwSCARkw\n" + + "ggEVMIHkoIHhoIHepIHbMIHYMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50\n" + + "cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0Ff\n" + + "SW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UE\n" + + "CxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50\n" + + "cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYD\n" + + "VQQDEwRDUkwxMCygKqAohiZodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9D\n" + + "bGllbnQxLmNybDArBgNVHRAEJDAigA8xOTk5MTAxMjE5MjQzMFqBDzIwMTkx\n" + + "MDEyMTkyNDMwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUxPucKXuXzUyW\n" + + "/O5bs8qZdIuV6kwwHQYDVR0OBBYEFMT7nCl7l81MlvzuW7PKmXSLlepMMAwG\n" + + "A1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI\n" + + "hvcNAQEEBQADgYEAP66K8ddmAwWePvrqHEa7pFuPeJoSSJn59DXeDDYHAmsQ\n" + + "OokUgZwxpnyyQbJq5wcBoUv5nyU7lsqZwz6hURzzwy5E97BnRqqS5TvaHBkU\n" + + "ODDV4qIxJS7x7EU47fgGWANzYrAQMY9Av2TgXD7FTx/aEkP/TOYGJqibGapE\n" + + "PHayXOw=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Entrust.net_Secure_Server_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UE\n" + + "BhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50\n" + + "cnVzdC5uZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl\n" + + "MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UE\n" + + "AxMxRW50cnVzdC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1\n" + + "dGhvcml0eTAeFw05OTA1MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQsw\n" + + "CQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3\n" + + "dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlh\n" + + "Yi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVkMTow\n" + + "OAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp\n" + + "b24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0\n" + + "VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/I0dNxScZgSYMVHIN\n" + + "iC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3wkrYKZImZNHk\n" + + "mGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OCAdcwggHT\n" + + "MBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHboIHY\n" + + "pIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5\n" + + "BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChs\n" + + "aW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBM\n" + + "aW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENl\n" + + "cnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNo\n" + + "dHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAi\n" + + "gA8xOTk5MDUyNTE2MDk0MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMC\n" + + "AQYwHwYDVR0jBBgwFoAU8BdiE1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYE\n" + + "FPAXYhNVPbP/CgBr+1CEl/PtYtAaMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9\n" + + "B0EABAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEFBQADgYEAkNwwAvpkdMKn\n" + + "CqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN95K+8cPV1ZVqBLssziY2Zcgx\n" + + "xufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd2cNgQ4xYDiKWL2KjLB+6\n" + + "rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Equifax_Secure_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQG\n" + + "EwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1\n" + + "cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4\n" + + "MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgx\n" + + "LTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0\n" + + "eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2R\n" + + "FGiYCh7+2gRvE4RiIcPRfM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO\n" + + "/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuv\n" + + "K9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAGA1UdHwRp\n" + + "MGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEt\n" + + "MCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5\n" + + "MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjAL\n" + + "BgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gjIBBPM5iQn9Qw\n" + + "HQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMBAf8w\n" + + "GgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GB\n" + + "AFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y\n" + + "7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2u\n" + + "FHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Equifax_Secure_Global_eBusiness_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJV\n" + + "UzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1\n" + + "aWZheCBTZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0\n" + + "MDAwMFoXDTIwMDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoT\n" + + "E0VxdWlmYXggU2VjdXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJl\n" + + "IEdsb2JhbCBlQnVzaW5lc3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw\n" + + "gYkCgYEAuucXkAJlsTRVPEnCUdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQy\n" + + "td4zjTov2/KaelpzmKNc6fuKcxtc58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORR\n" + + "OhI8bIpaVIRw28HFkM9yRcuoWcDNM50/o5brhTMhHD4ePmBudpxnhcXIw2EC\n" + + "AwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAHMA8GA1UdEwEB/wQFMAMBAf8w\n" + + "HwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0OBBYEFL6o\n" + + "oHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUAA4GBADDiAVGqx+pf\n" + + "2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkAZ70Br83gcfxa\n" + + "z2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv8qIYNMR1\n" + + "pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Equifax_Secure_eBusiness_CA_1.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJV\n" + + "UzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1\n" + + "aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcN\n" + + "MjAwNjIxMDQwMDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZh\n" + + "eCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2lu\n" + + "ZXNzIENBLTEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fe\n" + + "k6lfWg0XTzQaDJj0ItlZ1MRoRvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5\n" + + "/VGcqiTZ9J2DKocKIdMSODRsjQBuWqDZQu4aIZX5UkxVWsUPOE9G+m34LjXW\n" + + "HXzr4vCwdYDIqROsvojvOm6rXyo4YgKwEnv+j6YDAgMBAAGjZjBkMBEGCWCG\n" + + "SAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEp4\n" + + "MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRKeDJSEdtZFjZe38EUNkBq\n" + + "R3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZMzfmpTMANmvPMZWnm\n" + + "JXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+WB5Hh1Q+WKG1\n" + + "tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN/Bf+KpYr\n" + + "tWKmpj29f5JZzVoqgrI3eQ==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Equifax_Secure_eBusiness_CA_2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQG\n" + + "EwJVUzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlm\n" + + "YXggU2VjdXJlIGVCdXNpbmVzcyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5\n" + + "MDYyMzEyMTQ0NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkVxdWlmYXgg\n" + + "U2VjdXJlMSYwJAYDVQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0Et\n" + + "MjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF\n" + + "7Y6yEb3+6+e0dMKP/wXn2Z0GvxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKD\n" + + "pkWNYmi7hRsgcDKqQM2mll/EcTc/BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HM\n" + + "HMg3OrmXUqesxWoklE6ce8/AatbfIb0CAwEAAaOCAQkwggEFMHAGA1UdHwRp\n" + + "MGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORXF1aWZheCBT\n" + + "ZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNpbmVzcyBDQS0y\n" + + "MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkwNjIzMTIxNDQ1WjAL\n" + + "BgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBqy/3YIHqngnYw\n" + + "HQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQFMAMBAf8w\n" + + "GgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GB\n" + + "AAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy\n" + + "0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkt\n" + + "y3D1E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // GTE_CyberTrust_Global_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgw\n" + + "FgYDVQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRy\n" + + "dXN0IFNvbHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3Qg\n" + + "R2xvYmFsIFJvb3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1\n" + + "MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYD\n" + + "VQQLEx5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMT\n" + + "GkdURSBDeWJlclRydXN0IEdsb2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUA\n" + + "A4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4usJTQGz0O9pTAipTHBsiQl8i4\n" + + "ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcqlHHK6XALn\n" + + "ZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8F\n" + + "LztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3rGwnpXtlR22ciYaQqPEh3\n" + + "46B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l93PR2VX2bY1QY6fDq\n" + + "81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0PlZPvy5TYnh+d\n" + + "XIVtx6quTx8itc2VrbqnzPmrC3p/\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // GTE_CyberTrust_Root_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIB+jCCAWMCAgGjMA0GCSqGSIb3DQEBBAUAMEUxCzAJBgNVBAYTAlVTMRgw\n" + + "FgYDVQQKEw9HVEUgQ29ycG9yYXRpb24xHDAaBgNVBAMTE0dURSBDeWJlclRy\n" + + "dXN0IFJvb3QwHhcNOTYwMjIzMjMwMTAwWhcNMDYwMjIzMjM1OTAwWjBFMQsw\n" + + "CQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMRwwGgYDVQQD\n" + + "ExNHVEUgQ3liZXJUcnVzdCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB\n" + + "iQKBgQC45k+625h8cXyvRLfTD0bZZOWTwUKOx7pJjTUteueLveUFMVnGsS8K\n" + + "DPufpz+iCWaEVh43KRuH6X4MypqfpX/1FZSj1aJGgthoTNE3FQZor734sLPw\n" + + "KfWVWgkWYXcKIiXUT0Wqx73llt/51KiOQswkwB6RJ0q1bQaAYznEol44AwID\n" + + "AQABMA0GCSqGSIb3DQEBBAUAA4GBABKzdcZfHeFhVYAA1IFLezEPI2PnPfMD\n" + + "+fQ2qLvZ46WXTeorKeDWanOB5sCJo9Px4KWlIjeaY8JIILTbcuPI9tl8vrGv\n" + + "U9oUtCG41tWW4/5ODFlitppK+ULdjG+BqXH/9ApybW1EDp3zdHSo1TRJ6V6e\n" + + "6bR64eVaH4QwnNOfpSXY\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // GeoTrust_Global_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYT\n" + + "AlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVz\n" + + "dCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBC\n" + + "MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UE\n" + + "AxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n" + + "MIIBCgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEH\n" + + "CIjaWC9mOSm9BXiLnTjoBbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlC\n" + + "GDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7\n" + + "csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAj\n" + + "Nvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdRe\n" + + "JivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQAB\n" + + "o1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9\n" + + "qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1luMrMTjANBgkq\n" + + "hkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Qzxpe\n" + + "R+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWV\n" + + "Yrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF\n" + + "PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot\n" + + "2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeX\n" + + "xx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm\n" + + "Mw==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // GlobalSign_Root_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDdTCCAl2gAwIBAgILAgAAAAAA1ni3lAUwDQYJKoZIhvcNAQEEBQAwVzEL\n" + + "MAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNV\n" + + "BAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05\n" + + "ODA5MDExMjAwMDBaFw0xNDAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkw\n" + + "FwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRsw\n" + + "GQYDVQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUA\n" + + "A4IBDwAwggEKAoIBAQDaDuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR\n" + + "4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc\n" + + "71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4\n" + + "bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgK\n" + + "OOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMW\n" + + "ea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DP\n" + + "AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIABjAdBgNVHQ4EFgQUYHtmGkUNl8qJ\n" + + "UC99BM00qP/8/UswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOC\n" + + "AQEArqqf/LfSyx9fOSkoGJ40yWxPbxrwZKJwSk8ThptgKJ7ogUmYfQq75bCd\n" + + "PTbbjwVR/wkxKh/diXeeDy5slQTthsu0AD+EAk2AaioteAuubyuig0SDH81Q\n" + + "gkwkr733pbTIWg/050deSY43lv6aiAU62cDbKYfmGZZHpzqmjIs8d/5GY6dT\n" + + "2iHRrH5Jokvmw2dZL7OKDrssvamqQnw1wdh/1acxOk5jQzmvCLBhNIzTmKlD\n" + + "NPYPhyk7ncJWWJh3w/cbrPad+D6qp1RF8PX51TFl/mtYnHGzHtdS6jIX/EBg\n" + + "Hcl5JLL2bP2oZg6C3ZjL2sJETy6ge/L3ayx2EYRGinij4w==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // RSA_Root_Certificate_1.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlD\n" + + "ZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu\n" + + "Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRp\n" + + "b24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNv\n" + + "bS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYy\n" + + "NjAwMjIzM1oXDTE5MDYyNjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0\n" + + "IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4x\n" + + "NTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24g\n" + + "QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x\n" + + "IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3\n" + + "DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFlLWLU2f\n" + + "NUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChM\n" + + "MFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqYJJgpp0lZpd34\n" + + "t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliEZwgs3x/b\n" + + "e0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJn0Wu\n" + + "PIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A\n" + + "PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // RSA_Security_1024_v3.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICXDCCAcWgAwIBAgIQCgEBAQAAAnwAAAALAAAAAjANBgkqhkiG9w0BAQUF\n" + + "ADA6MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0Eg\n" + + "U2VjdXJpdHkgMTAyNCBWMzAeFw0wMTAyMjIyMTAxNDlaFw0yNjAyMjIyMDAx\n" + + "NDlaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJT\n" + + "QSBTZWN1cml0eSAxMDI0IFYzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB\n" + + "gQDV3f5mCc8kPD6ugU5OisRpgFtZO9+5TUzKtS3DJy08rwBCbbwoppbPf9dY\n" + + "rIMKo1W1exeQFYRMiu4mmdxY78c4pqqv0I5CyGLXq6yp+0p9v+r+Ek3d/yYt\n" + + "bzZUaMjShFbuklNhCbM/OZuoyZu9zp9+1BlqFikYvtc6adwlWzMaUQIDAQAB\n" + + "o2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSME\n" + + "GDAWgBTEwBykB5T9zU0B1FTapQxf3q4FWjAdBgNVHQ4EFgQUxMAcpAeU/c1N\n" + + "AdRU2qUMX96uBVowDQYJKoZIhvcNAQEFBQADgYEAPy1q4yZDlX2Jl2X7deRy\n" + + "HUZXxGFraZ8SmyzVWujAovBDleMf6XbN3Ou8k6BlCsdNT1+nr6JGFLkM88y9\n" + + "am63nd4lQtBU/55oc2PcJOsiv6hy8l4A4Q1OOkNumU4/iXgDmMrzVcydro7B\n" + + "qkWY+o8aoI2II/EVQQ2lRj6RP4vr93E=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // RSA_Security_2048_v3.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUF\n" + + "ADA6MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0Eg\n" + + "U2VjdXJpdHkgMjA0OCBWMzAeFw0wMTAyMjIyMDM5MjNaFw0yNjAyMjIyMDM5\n" + + "MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJT\n" + + "QSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n" + + "CgKCAQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37\n" + + "RqtBaB4Y6lXIL5F4iSj7Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E\n" + + "0S1PRsNO3Ng3OTsor8udGuorryGlwSMiuLgbWhOHV4PR8CDn6E8jQrAApX2J\n" + + "6elhc5SYcSa8LWrg903w8bYqODGBDSnhAMFRD0xS+ARaqn1y07iHKrtjEAMq\n" + + "s6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2PcYJk5qjEoAAVZkZR73QpXzD\n" + + "uvsf9/UP+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszACwIDAQABo2Mw\n" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAW\n" + + "gBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4EFgQUB8NRMKSq6UWuNST6\n" + + "/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmYv/3V\n" + + "EhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5g\n" + + "EydxiKRz44Rj0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+\n" + + "f00/FGj1EVDVwfSQpQgdMWD/YIwjVAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJq\n" + + "aHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395nzIlQnQFgCi/vcEk\n" + + "llgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kA\n" + + "pKnXwiJPZ9d37CAFYd4=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // TC_TrustCenter__Germany__Class_2_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDXDCCAsWgAwIBAgICA+owDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYT\n" + + "AkRFMRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYD\n" + + "VQQKEzFUQyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3\n" + + "b3JrcyBHbWJIMSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAyIENB\n" + + "MSkwJwYJKoZIhvcNAQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAe\n" + + "Fw05ODAzMDkxMTU5NTlaFw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJE\n" + + "RTEQMA4GA1UECBMHSGFtYnVyZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UE\n" + + "ChMxVEMgVHJ1c3RDZW50ZXIgZm9yIFNlY3VyaXR5IGluIERhdGEgTmV0d29y\n" + + "a3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTEp\n" + + "MCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVAdHJ1c3RjZW50ZXIuZGUwgZ8w\n" + + "DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANo46O0yAClxgwENv4wB3NrGrTmk\n" + + "qYov1YtcaF9QxmL1Zr3KkSLsqh1R1z2zUbKDTl3LSbDwTFXlay3HhQswHJJO\n" + + "gtTKAu33b77c4OMUuAVT8pr0VotanoWT0bSCVq5Nu6hLVxa8/vhYnvgpjbB7\n" + + "zXjJT6yLZwzxnPv8V5tXXE8NAgMBAAGjazBpMA8GA1UdEwEB/wQFMAMBAf8w\n" + + "DgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3LnRy\n" + + "dXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G\n" + + "CSqGSIb3DQEBBAUAA4GBAIRS+yjf/x91AbwBvgRWl2p0QiQxg/lGsQaKic+W\n" + + "LDO/jLVfenKhhQbOhvgFjuj5Jcrag4wGrOs2bYWRNAQ29ELw+HkuCkhcq8xR\n" + + "T3h2oNmsGb0q0WkEKJHKNhAngFdb0lz1wlurZIFjdFH0l7/NEij3TWZ/p/Ac\n" + + "ASZ4smZHcFFk\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // TC_TrustCenter__Germany__Class_3_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDXDCCAsWgAwIBAgICA+swDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYT\n" + + "AkRFMRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYD\n" + + "VQQKEzFUQyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3\n" + + "b3JrcyBHbWJIMSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAzIENB\n" + + "MSkwJwYJKoZIhvcNAQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAe\n" + + "Fw05ODAzMDkxMTU5NTlaFw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJE\n" + + "RTEQMA4GA1UECBMHSGFtYnVyZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UE\n" + + "ChMxVEMgVHJ1c3RDZW50ZXIgZm9yIFNlY3VyaXR5IGluIERhdGEgTmV0d29y\n" + + "a3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTEp\n" + + "MCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVAdHJ1c3RjZW50ZXIuZGUwgZ8w\n" + + "DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALa0wTUFLg2N7KBAahwOJ6ZQkmtQ\n" + + "GwfeLud2zODa/ISoXoxjaitN2U4CdhHBC/KNecoAtvGwDtf7pBc9r6tpepYn\n" + + "v68zoZoqWarEtTcI8hKlMbZD9TKWcSgoq40oht+77uMMfTDWw1Krj10nnGvA\n" + + "o+cFa1dJRLNu6mTP0o56UHd3AgMBAAGjazBpMA8GA1UdEwEB/wQFMAMBAf8w\n" + + "DgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3LnRy\n" + + "dXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G\n" + + "CSqGSIb3DQEBBAUAA4GBABY9xs3Bu4VxhUafPiCPUSiZ7C1FIWMjWwS7TJC4\n" + + "iJIETb19AaM/9uzO8d7+feXhPrvGq14L3T2WxMup1Pkm5gZOngylerpuw3yC\n" + + "GdHHsbHD2w2Om0B8NwvxXej9H5CIpQ5ON2QhqE6NtJ/x3kit1VYYUimLRzQS\n" + + "CdS7kjXvD9s0\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Thawte_Personal_Basic_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDITCCAoqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMC\n" + + "WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du\n" + + "MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm\n" + + "aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFBl\n" + + "cnNvbmFsIEJhc2ljIENBMSgwJgYJKoZIhvcNAQkBFhlwZXJzb25hbC1iYXNp\n" + + "Y0B0aGF3dGUuY29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVow\n" + + "gcsxCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNV\n" + + "BAcTCUNhcGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAm\n" + + "BgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24xITAfBgNV\n" + + "BAMTGFRoYXd0ZSBQZXJzb25hbCBCYXNpYyBDQTEoMCYGCSqGSIb3DQEJARYZ\n" + + "cGVyc29uYWwtYmFzaWNAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOB\n" + + "jQAwgYkCgYEAvLyTU23AUE+CFeZIlDWmWr5vQvoPR+53dXLdjUmbllegeNTK\n" + + "P1GzaQuRdhciB5dqxFGTS+CN7zeVoQxN2jSQHReJl+A1OFdKwPQIcOk8RHtQ\n" + + "fmGakOMj04gRRif1CwcOu93RfyAKiLlWCy4cgNrx454p7xS9CkT7G1sY0b8j\n" + + "kyECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOB\n" + + "gQAt4plrsD16iddZopQBHyvdEktTwq1/qqcAXJFAVyVKOKqEcLnZgA+le1z7\n" + + "c8a914phXAPjLSeoF+CEhULcXpvGt7Jtu3Sv5D/Lp7ew4F2+eIMllNLbgQ95\n" + + "B21P9DkVWlIBe94y1k049hJcBlDfBVu9FEuh3ym6O0GN92NWod8isQ==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Thawte_Personal_Freemail_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDLTCCApagAwIBAgIBADANBgkqhkiG9w0BAQQFADCB0TELMAkGA1UEBhMC\n" + + "WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du\n" + + "MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm\n" + + "aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEkMCIGA1UEAxMbVGhhd3RlIFBl\n" + + "cnNvbmFsIEZyZWVtYWlsIENBMSswKQYJKoZIhvcNAQkBFhxwZXJzb25hbC1m\n" + + "cmVlbWFpbEB0aGF3dGUuY29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIz\n" + + "NTk1OVowgdExCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUx\n" + + "EjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRp\n" + + "bmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24x\n" + + "JDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBGcmVlbWFpbCBDQTErMCkGCSqG\n" + + "SIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhhd3RlLmNvbTCBnzANBgkq\n" + + "hkiG9w0BAQEFAAOBjQAwgYkCgYEA1GnX1LCUZFtx6UfYDFG26nKRsIRefS0N\n" + + "j3sS34UldSh0OkIsYyeflXtL734Zhx2G6qPduc6WZBrCFG5ErHzmj+hND3Ef\n" + + "QDimAKOHePb5lIZererAXnbr2RSjXW56fAylS1V/Bhkpf56aJtVquzgkCGqY\n" + + "x7Hao5iR/Xnb5VrEHLkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq\n" + + "hkiG9w0BAQQFAAOBgQDH7JJ+Tvj1lqVnYiqk8E0RYNBvjWBYYawmu1I1XAjP\n" + + "MPuoSpaKH2JCI4wXD/S6ZJwXrEcp352YXtJsYHFcoqzceePnbgBHH7UNKOgC\n" + + "neSa/RP0ptl8sfjcXyMmCZGAc9AUG95DqYMl8uacLxXK/qarigd1iwzdUYRr\n" + + "5PjRzneigQ==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Thawte_Personal_Premium_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDKTCCApKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBzzELMAkGA1UEBhMC\n" + + "WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du\n" + + "MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm\n" + + "aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEjMCEGA1UEAxMaVGhhd3RlIFBl\n" + + "cnNvbmFsIFByZW1pdW0gQ0ExKjAoBgkqhkiG9w0BCQEWG3BlcnNvbmFsLXBy\n" + + "ZW1pdW1AdGhhd3RlLmNvbTAeFw05NjAxMDEwMDAwMDBaFw0yMDEyMzEyMzU5\n" + + "NTlaMIHPMQswCQYDVQQGEwJaQTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIw\n" + + "EAYDVQQHEwlDYXBlIFRvd24xGjAYBgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5n\n" + + "MSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMSMw\n" + + "IQYDVQQDExpUaGF3dGUgUGVyc29uYWwgUHJlbWl1bSBDQTEqMCgGCSqGSIb3\n" + + "DQEJARYbcGVyc29uYWwtcHJlbWl1bUB0aGF3dGUuY29tMIGfMA0GCSqGSIb3\n" + + "DQEBAQUAA4GNADCBiQKBgQDJZtn4B0TPuYwu8KHvE0VsBd/eJxZRNkERbGw7\n" + + "7f4QfRKe5ZtCmv5gMcNmt3M6SK5O0DI3lIi1DbbZ8/JE2dWIEt12TfIa/G8j\n" + + "Hnrx2JhFTgcQ7xZC0EN1bUre4qrJMf8fAHB8Zs8QJQi6+u4A6UYDZicRFTuq\n" + + "W/KY3TZCstqIdQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3\n" + + "DQEBBAUAA4GBAGk2ifc0KjNyL2071CKyuG+axTZmDhs8obF1Wub9NdP4qPIH\n" + + "b4Vnjt4rueIXsDqg8A6iAJrf8xQVbrvIhVqYgPn/vnQdPfP+MCXRNzRn+qVx\n" + + "eTBhKXLA4CxM+1bkOqhv5TJZUtt1KFBZDPgLGeSs2a+WjS9Q2wfD6h+rM+D1\n" + + "KzGJ\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Thawte_Premium_Server_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMC\n" + + "WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du\n" + + "MR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2Vy\n" + + "dGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3Rl\n" + + "IFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNl\n" + + "cnZlckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1\n" + + "OVowgc4xCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQ\n" + + "BgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMUVGhhd3RlIENvbnN1bHRpbmcg\n" + + "Y2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24x\n" + + "ITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3\n" + + "DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0B\n" + + "AQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhI\n" + + "NTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQug2SBhRz1JPL\n" + + "lyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/qgeN\n" + + "9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B\n" + + "AQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI\n" + + "hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZ\n" + + "a4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcU\n" + + "Qg==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Thawte_Server_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMC\n" + + "WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du\n" + + "MR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2Vy\n" + + "dGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3Rl\n" + + "IFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0\n" + + "ZS5jb20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkG\n" + + "A1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2Fw\n" + + "ZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UE\n" + + "CxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQ\n" + + "VGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRz\n" + + "QHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I\n" + + "/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC\n" + + "6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCXL+eQbcAoQpnX\n" + + "TEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzARMA8G\n" + + "A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWD\n" + + "TSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e\n" + + "QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdni\n" + + "TCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Thawte_Time_Stamping_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICoTCCAgqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBizELMAkGA1UEBhMC\n" + + "WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmls\n" + + "bGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmlj\n" + + "YXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwHhcNOTcw\n" + + "MTAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBizELMAkGA1UEBhMCWkExFTAT\n" + + "BgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzAN\n" + + "BgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24x\n" + + "HzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwgZ8wDQYJKoZIhvcN\n" + + "AQEBBQADgY0AMIGJAoGBANYrWHhhRYZT6jR7UZztsOYuGA7+4F+oJ9O0yeB8\n" + + "WU4WDnNUYMF/9p8u6TqFJBU820cEY8OexJQaWt9MevPZQx08EHp5JduQ/vBR\n" + + "5zDWQQD9nyjfeb6Uu522FOMjhdepQeBMpHmwKxqL8vg7ij5FrHGSALSQQZj7\n" + + "X+36ty6K+Ig3AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN\n" + + "AQEEBQADgYEAZ9viwuaHPUCDhjc1fR/OmsMMZiCouqoEiYbC9RAIDb/LogWK\n" + + "0E02PvTX72nGXuSwlG9KuefeW4i2e9vjJ+V2w/A1wcu1J5szedyQpgCed/r8\n" + + "zSeUQhac0xxo7L9c3eWpexAKMnRUEzGLhQOEkbdYATAUOK8oyvyxUBkZCayJ\n" + + "SdM=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // UTN-USER_First-Network_Applications.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUF\n" + + "ADCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0\n" + + "IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEw\n" + + "HwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVU\n" + + "Ti1VU0VSRmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0\n" + + "ODM5WhcNMTkwNzA5MTg1NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgT\n" + + "AlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVT\n" + + "RVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVz\n" + + "dC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3QtTmV0d29yayBBcHBsaWNh\n" + + "dGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCz+5Gh5DZV\n" + + "hawGNFugmliy+LUPBXeDrjKxdpJo7CNKyXY/45y2N3kDuatpjQclthln5LAb\n" + + "GHNhSuh+zdMvZOOmfAz6F4CjDUeJT1FxL+78P/m4FoCHiZMlIJpDgmkkdihZ\n" + + "NaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXuOzr0hAReYFmnjDRy7rh4\n" + + "xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1axwiP8vv\n" + + "/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6gyN7i\n" + + "gEL66S/ozjIEj3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQD\n" + + "AgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPqGydvguul49Uuo1hXf\n" + + "8NPhahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9jcmwudXNlcnRydXN0\n" + + "LmNvbS9VVE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0G\n" + + "CSqGSIb3DQEBBQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXh\n" + + "i6r/fWRRzwr/vH3YIWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUq\n" + + "f9FuVSTiuwL7MT++6LzsQCv4AdRWOOTKRIK1YSAhZ2X28AvnNPilwpyjXEAf\n" + + "hZOVBt5P1CeptqX8Fs1zMT+4ZSfP1FMa8Kxun08FDAOBp4QpxFq9ZFdyrTvP\n" + + "NximmMatBrTcCKME1SmklpoSZ0qMYEWd8SOasACcaLWYUNPvji6SZbFIPiG+\n" + + "FTAqDbUMo2s/rn9X9R+WfN9v3YIwLGUbQErNaLly7HF27FSOH4UMAWr6pjis\n" + + "H8SE\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // ValiCert_Class_1_VA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlD\n" + + "ZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu\n" + + "Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRp\n" + + "b24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNv\n" + + "bS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYy\n" + + "NTIyMjM0OFoXDTE5MDYyNTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0\n" + + "IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4x\n" + + "NTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24g\n" + + "QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x\n" + + "IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3\n" + + "DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu9OqNSLwxlBfw\n" + + "8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m\n" + + "+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8YTfwggtFzVXSN\n" + + "dnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0LBwGlN+V\n" + + "YH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLWI8so\n" + + "gTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPw\n" + + "nXS3qT6gpf+2SQMT2iLM7XGCK5nPOrf1LXLI\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // ValiCert_Class_2_VA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlD\n" + + "ZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu\n" + + "Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRp\n" + + "b24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNv\n" + + "bS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYy\n" + + "NjAwMTk1NFoXDTE5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0\n" + + "IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4x\n" + + "NTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24g\n" + + "QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x\n" + + "IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3\n" + + "DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZUcOBVXc\n" + + "65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQ\n" + + "b7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QSv4dk+NoS/zcn\n" + + "wbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9vUJSZSWI4\n" + + "OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTuIYEZ\n" + + "oDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC\n" + + "W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // ValiCert_OCSP_Responder.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDSDCCArGgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBsjEkMCIGA1UEBxMb\n" + + "VmFsaUNlcnQgVmFsaWRhdGlvbiBOZXR3b3JrMRcwFQYDVQQKEw5WYWxpQ2Vy\n" + + "dCwgSW5jLjEsMCoGA1UECxMjQ2xhc3MgMSBWYWxpZGF0aW9uIEF1dGhvcml0\n" + + "eSAtIE9DU1AxITAfBgNVBAMTGGh0dHA6Ly93d3cudmFsaWNlcnQubmV0LzEg\n" + + "MB4GCSqGSIb3DQEJARYRaW5mb0B2YWxpY2VydC5jb20wHhcNMDAwMjEyMTE1\n" + + "MDA1WhcNMDUwMjEwMTE1MDA1WjCBsjEkMCIGA1UEBxMbVmFsaUNlcnQgVmFs\n" + + "aWRhdGlvbiBOZXR3b3JrMRcwFQYDVQQKEw5WYWxpQ2VydCwgSW5jLjEsMCoG\n" + + "A1UECxMjQ2xhc3MgMSBWYWxpZGF0aW9uIEF1dGhvcml0eSAtIE9DU1AxITAf\n" + + "BgNVBAMTGGh0dHA6Ly93d3cudmFsaWNlcnQubmV0LzEgMB4GCSqGSIb3DQEJ\n" + + "ARYRaW5mb0B2YWxpY2VydC5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ\n" + + "AoGBAMeML6fDQIc7PdfEmlgUZArDCDliGs/S66nxaXSKyg5adsyiUk7Q88R6\n" + + "tfimHLujp6RTh1uNwAC71WYk53TGFsivyANi1TKHolKRRJSVqEdDbaVInPZM\n" + + "ddVPYufJ/3v0JIynvCh2tTKgJXO3Ry94+Eb5hxTwd/wKd+hP/Ywf+mLZAgMB\n" + + "AAGjbDBqMA8GCSsGAQUFBzABBQQCBQAwEwYDVR0lBAwwCgYIKwYBBQUHAwkw\n" + + "CwYDVR0PBAQDAgGGMDUGCCsGAQUFBwEBBCkwJzAlBggrBgEFBQcwAYYZaHR0\n" + + "cDovL29jc3AyLnZhbGljZXJ0Lm5ldDANBgkqhkiG9w0BAQUFAAOBgQAVxeC4\n" + + "NHISBiCoYpWT0byTupCr3E6Njo2YTOMy9Ss/s5f7qqKtQJetaL1crVMO0Kaz\n" + + "DawamY2qMB7PDnD/ArB3ZYPN2gdcUs1Zu6LI4rQWg4/UlXmTLei/RJMxkjDT\n" + + "NDTxEPshrC70w11kY3qZ4ZqrQh1IZqZ3N7hVPK3+ZbBi6Q==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_1_Public_Primary_Certification_Authority.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8x\n" + + "CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UE\n" + + "CxMuQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv\n" + + "cml0eTAeFw05NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNV\n" + + "BAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh\n" + + "c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCB\n" + + "nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Rm/baNWYS2ZSHH2Z965jeu3\n" + + "noaACpEO+jglr0aIguVzqKCbJF0NH8xlbgyw0FaEGIeaBpsQoXPftFg5a27B\n" + + "9hXVqKg/qhIGjTGsf7A01480Z4gJzRQR4k5FVmkfeAKA2txHkSm7NsljXMXg\n" + + "1y2He6G3MrB7MLoqLzGq7qNn2tsCAwEAATANBgkqhkiG9w0BAQIFAAOBgQBM\n" + + "P7iLxmjf7kMzDl3ppssHhE16M/+SG/Q2rdiVIjZoEWx8QszznC7EBz8UsA9P\n" + + "/5CSdvnivErpj82ggAr3xSnxgiJduLHdgSOjeyUVRjB5FvjqBUuUfx3CHMjj\n" + + "t/QQQDwTw18fU+hI5Ia0e6E1sHslurjTjqs/OJ0ANACY89FxlA==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_1_Public_Primary_Certification_Authority_-_G2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcEx\n" + + "CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UE\n" + + "CxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv\n" + + "cml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAt\n" + + "IEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBU\n" + + "cnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVow\n" + + "gcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoG\n" + + "A1UECxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1\n" + + "dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5j\n" + + "LiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2ln\n" + + "biBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCq\n" + + "0Lq+Fi24g9TK0g+8djHKlNgdk4xWArzZbxpvUjZudVYKVdPfQ4chEWWKfo+9\n" + + "Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIqWpDBucSmFc/IReumXY6c\n" + + "PvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQIDAQABMA0G\n" + + "CSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0Jh9Zr\n" + + "bWB85a7FkCMMXErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2ul\n" + + "uIncrKTdcu1OofdPvAbT6shkdHvClUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4i\n" + + "P/68DzFc6PLZ\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_1_Public_Primary_Certification_Authority_-_G3.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHK\n" + + "MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNV\n" + + "BAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5\n" + + "IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBD\n" + + "BgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlm\n" + + "aWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3\n" + + "MTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24s\n" + + "IEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNV\n" + + "BAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQg\n" + + "dXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFBy\n" + + "aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI\n" + + "hvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4nN493GwTFtl63SRR\n" + + "ZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO8ESlV8dAWB6j\n" + + "Rx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjVojYJrKsh\n" + + "JlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjbPG7P\n" + + "oBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP2\n" + + "6KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHh\n" + + "v2Vrn5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQ\n" + + "BfGfMY1aqtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/N\n" + + "y9Sn2WCVhDr4wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUf\n" + + "xJM8/XmPBNQ+T+r3ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFM\n" + + "DSZl4kSAHsef493oCtrspSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5\n" + + "SCJ5ShkPshw+IHTZasO+8ih4E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXV\n" + + "OBRgmaNL3gaWcSzy27YfpO8/7g==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_1_Public_Primary_OCSP_Responder.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDnjCCAwegAwIBAgIQK2jUo0aexTsoCas4XX8nIDANBgkqhkiG9w0BAQUF\n" + + "ADBfMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1\n" + + "BgNVBAsTLkNsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB\n" + + "dXRob3JpdHkwHhcNMDAwODA0MDAwMDAwWhcNMDQwODAzMjM1OTU5WjCBpzEX\n" + + "MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy\n" + + "dXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczov\n" + + "L3d3dy52ZXJpc2lnbi5jb20vUlBBIChjKTAwMS4wLAYDVQQDEyVDbGFzcyAx\n" + + "IFB1YmxpYyBQcmltYXJ5IE9DU1AgUmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEB\n" + + "AQUAA4GNADCBiQKBgQC57V56Ondfzl86UvzNZPdxtW9qlsZZklWUXS9bLsER\n" + + "6iaKy6eBPPZaRN56Ey/9WlHZezcmSsAnPwQDalbBgyzhb1upVFAkSsYuekyh\n" + + "WzdUJCExH6F4GHansXDaItBq/gdiQMb39pt9DAa4S8co5GYjhFHvRreT2IEz\n" + + "y+U2rMboBQIDAQABo4IBEDCCAQwwIAYDVR0RBBkwF6QVMBMxETAPBgNVBAMT\n" + + "CE9DU1AgMS0xMDEGA1UdHwQqMCgwJqAkoCKGIGh0dHA6Ly9jcmwudmVyaXNp\n" + + "Z24uY29tL3BjYTEuY3JsMBMGA1UdJQQMMAoGCCsGAQUFBwMJMEIGCCsGAQUF\n" + + "BwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJpc2lnbi5j\n" + + "b20vb2NzcC9zdGF0dXMwRAYDVR0gBD0wOzA5BgtghkgBhvhFAQcBATAqMCgG\n" + + "CCsGAQUFBwIBFhxodHRwczovL3d3dy52ZXJpc2lnbi5jb20vUlBBMAkGA1Ud\n" + + "EwQCMAAwCwYDVR0PBAQDAgeAMA0GCSqGSIb3DQEBBQUAA4GBAHCQ3bjkvlMX\n" + + "fH8C6dX3i5mTMWCNfuZgayTvYKzSzpHegG0JpNO4OOVEynJeDS3Bd5y9LAN4\n" + + "KY2kpXeH9fErJq3MB2w6VFoo4AnzTQoEytRYaQuns/XdAaXn3PAfusFdkI2z\n" + + "6k/BEVmXarIrE7HarZehs7GgIFvKMquNzxPwHynD\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_2_Public_Primary_Certification_Authority.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICPDCCAaUCEC0b/EoXjaOR6+f/9YtFvgswDQYJKoZIhvcNAQECBQAwXzEL\n" + + "MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQL\n" + + "Ey5DbGFzcyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y\n" + + "aXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UE\n" + + "BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz\n" + + "cyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGf\n" + + "MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2WoujDWojg4BrzzmH9CETMwZM\n" + + "JaLtVRKXxaeAufqDwSCg+i8VDXyhYGt+eSz6Bg86rvYbb7HS/y8oUl+DfUvE\n" + + "erf4Zh+AVPy3wo5ZShRXRtGak75BkQO7FYCTXOvnzAhsPz6zSvz/S2wj1VCC\n" + + "JkQZjiPDceoZJEcEnnW/yKYAHwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBAIob\n" + + "K/o5wXTXXtgZZKJYSi034DNHD6zt96rbHuSLBlxgJ8pFUs4W7z8GZOeUaHxg\n" + + "MxURaa+dYo2jA1Rrpr7l7gUYYAS/QoD90KioHgE796Ncr6Pc5iaAIzy4RHT3\n" + + "Cq5Ji2F4zCS/iIqnDupzGUH9TQPwiNHleI2lKk/2lw0Xd8rY\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_2_Public_Primary_Certification_Authority_-_G2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHB\n" + + "MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNV\n" + + "BAsTM0NsYXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRo\n" + + "b3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIEluYy4g\n" + + "LSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24g\n" + + "VHJ1c3QgTmV0d29yazAeFw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTla\n" + + "MIHBMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6\n" + + "BgNVBAsTM0NsYXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB\n" + + "dXRob3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIElu\n" + + "Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNp\n" + + "Z24gVHJ1c3QgTmV0d29yazCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA\n" + + "p4gBIXQs5xoD8JjhlzwPIQjxnNuX6Zr8wgQGE75fUsjMHiwSViy4AWkszJkf\n" + + "rbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRCwiNPStjwDqL7MWzJ5m+Z\n" + + "Jwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cCAwEAATAN\n" + + "BgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9jinb3/\n" + + "7aHmZuovCfTK1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAX\n" + + "rXfMSTWqz9iP0b63GJZHc2pUIjRkLbYWm1lbtFFZOrMLFPQS32eg9K0yZF6x\n" + + "RnInjBJ7xUS0rg==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_2_Public_Primary_Certification_Authority_-_G3.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcox\n" + + "CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UE\n" + + "CxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkg\n" + + "VmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMG\n" + + "A1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZp\n" + + "Y2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcx\n" + + "NjIzNTk1OVowgcoxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwg\n" + + "SW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UE\n" + + "CxMxKGMpIDE5OTkgVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1\n" + + "c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJp\n" + + "bWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMIIBIjANBgkqhkiG\n" + + "9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwoNwtUs22e5LeWUJ92lvuCwTY+zYVY8\n" + + "1nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6tW8UvxDOJxOeBUebMXoT\n" + + "2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUYwZF7C9UT\n" + + "AJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9okoqQ\n" + + "HgiBVrKtaaNS0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjN\n" + + "qWm6o+sdDZykIKbBoMXRRkwXbdKsZj+WjOCE1Db/IlnF+RFgqF8EffIa9iVC\n" + + "YQ/ESrg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0JhU8wI1NQ0kdvekh\n" + + "ktdmnLfexbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf\n" + + "0xwLRtxyID+u7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydE\n" + + "p85EXdQbkJgNHkKUsQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377B\n" + + "MnMiIYtYgXsVkXq642RIsH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab\n" + + "5iXiQkWquJCtvgiPqQtCGJTPcjnhsUPgKM+351psE2tJs//jGHyJizNdrDPX\n" + + "p/naOlXJWBD5qu9ats9LS98q\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_2_Public_Primary_OCSP_Responder.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDnjCCAwegAwIBAgIQCUYX5h3Y1BygDKBi6HmKpzANBgkqhkiG9w0BAQUF\n" + + "ADBfMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1\n" + + "BgNVBAsTLkNsYXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB\n" + + "dXRob3JpdHkwHhcNMDAwODAxMDAwMDAwWhcNMDQwNzMxMjM1OTU5WjCBpzEX\n" + + "MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy\n" + + "dXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczov\n" + + "L3d3dy52ZXJpc2lnbi5jb20vUlBBIChjKTAwMS4wLAYDVQQDEyVDbGFzcyAy\n" + + "IFB1YmxpYyBQcmltYXJ5IE9DU1AgUmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEB\n" + + "AQUAA4GNADCBiQKBgQDQymMxYX9ENHwFfQs9apDLeUt3Cj9LxyPlwGItfpx+\n" + + "PoiHkdCs6E1Jh6KWkIrdBKUCP4yb6Yn+YqDiWr3I3bR45qVCkwhnAcAgTddc\n" + + "9F3as+M3plIaLExlTYqH2aij8UlUuzxcgFFoxvtJ/wtVqxXd+5rBuR10DbKM\n" + + "RF2J/J/5gwIDAQABo4IBEDCCAQwwIAYDVR0RBBkwF6QVMBMxETAPBgNVBAMT\n" + + "CE9DU1AgMS0yMDEGA1UdHwQqMCgwJqAkoCKGIGh0dHA6Ly9jcmwudmVyaXNp\n" + + "Z24uY29tL3BjYTIuY3JsMBMGA1UdJQQMMAoGCCsGAQUFBwMJMEIGCCsGAQUF\n" + + "BwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJpc2lnbi5j\n" + + "b20vb2NzcC9zdGF0dXMwRAYDVR0gBD0wOzA5BgtghkgBhvhFAQcBATAqMCgG\n" + + "CCsGAQUFBwIBFhxodHRwczovL3d3dy52ZXJpc2lnbi5jb20vUlBBMAkGA1Ud\n" + + "EwQCMAAwCwYDVR0PBAQDAgeAMA0GCSqGSIb3DQEBBQUAA4GBAB99CW4kRnUE\n" + + "nPMmm+M5bhfvvL2iG9IChIar0ECXLMRDiDcZayKoA3FQnSDcNmAgmnMtc1Vs\n" + + "WJsswrQ0LHozQsqR2elDr88e4PXEeqs/cmMeqTfhWzuIsxOGgpBXy1f/9Fa+\n" + + "It3jl6jhvCJDwt1N2/aBnpIUnjkPE1TegtjAXjSN\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_3_Public_Primary_Certification_Authority.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzEL\n" + + "MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQL\n" + + "Ey5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y\n" + + "aXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UE\n" + + "BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz\n" + + "cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGf\n" + + "MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69q\n" + + "RUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94f56TuZoAqiN91qyFomNFx3In\n" + + "zPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Olhec9vn2a\n" + + "/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBALtM\n" + + "EivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Dolbwdj2wsqFHMc9ikwFPw\n" + + "TtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNycAA9WjQKZ7aKQRUzk\n" + + "uxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_3_Public_Primary_Certification_Authority_-_G2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcEx\n" + + "CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UE\n" + + "CxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv\n" + + "cml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAt\n" + + "IEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBU\n" + + "cnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVow\n" + + "gcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoG\n" + + "A1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1\n" + + "dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5j\n" + + "LiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2ln\n" + + "biBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDM\n" + + "XtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4pO0M8RcPO/mn+SXX\n" + + "wc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg013gfqLptQ5GV\n" + + "j0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwIDAQABMA0G\n" + + "CSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSkU01U\n" + + "bSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i\n" + + "F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo\n" + + "1KpYoJ2daZH9\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_3_Public_Primary_Certification_Authority_-_G3.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHK\n" + + "MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNV\n" + + "BAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5\n" + + "IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBD\n" + + "BgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlm\n" + + "aWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3\n" + + "MTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24s\n" + + "IEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNV\n" + + "BAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQg\n" + + "dXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFBy\n" + + "aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI\n" + + "hvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2\n" + + "R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2tKmFZpGcmTNDo\n" + + "vFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUccLwg\n" + + "TS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+V\n" + + "k7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ\n" + + "Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJ\n" + + "OxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my\n" + + "/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f\n" + + "j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoA\n" + + "Wii/gt/4uhMdUIaC/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8S\n" + + "GhJouPtmmRQURVyu565pF4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbb\n" + + "o27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh\n" + + "/sVFuq1ruQp6Tk9LhO5L8X3dEQ==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_3_Public_Primary_OCSP_Responder.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDojCCAwugAwIBAgIQLpaev7ZibOx76XPM42zBhDANBgkqhkiG9w0BAQUF\n" + + "ADBfMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1\n" + + "BgNVBAsTLkNsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB\n" + + "dXRob3JpdHkwHhcNMDAwODA0MDAwMDAwWhcNMDQwODAzMjM1OTU5WjCBpzEX\n" + + "MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy\n" + + "dXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczov\n" + + "L3d3dy52ZXJpc2lnbi5jb20vUlBBIChjKTAwMS4wLAYDVQQDEyVDbGFzcyAz\n" + + "IFB1YmxpYyBQcmltYXJ5IE9DU1AgUmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEB\n" + + "AQUAA4GNADCBiQKBgQDx5AgOg7t140jluNum8Lmr6Txix141W9ACVBHYydFW\n" + + "uXZLuat65s269gwE1n7WsAplrE454/H3LaMlOe+wi8++2wxdbnD0B81w9zrA\n" + + "PjUW7XiMQ8/CJi5H1oZ9nPG+1mcMIiWkymXmH3p4KC8/BdsEIb/hRWb+PLeC\n" + + "7Vq4FhW5VQIDAQABo4IBFDCCARAwIAYDVR0RBBkwF6QVMBMxETAPBgNVBAMT\n" + + "CE9DU1AgMS0zMDUGA1UdHwQuMCwwKqAooCaGJGh0dHA6Ly9jcmwudmVyaXNp\n" + + "Z24uY29tL3BjYTMuMS4xLmNybDATBgNVHSUEDDAKBggrBgEFBQcDCTBCBggr\n" + + "BgEFBQcBAQQ2MDQwMgYIKwYBBQUHMAGmJhYkaHR0cDovL29jc3AudmVyaXNp\n" + + "Z24uY29tL29jc3Avc3RhdHVzMEQGA1UdIAQ9MDswOQYLYIZIAYb4RQEHAQEw\n" + + "KjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL1JQQTAJ\n" + + "BgNVHRMEAjAAMAsGA1UdDwQEAwIHgDANBgkqhkiG9w0BAQUFAAOBgQAC9lNj\n" + + "wKke8tCLMzCPSJtMsFa0g3FKvtxQ2PW24AvbvXhP6c8JNNopSZ0Bc1qRkYJU\n" + + "LBMK03cjzzf8Y96n4/a3tWlFKEnDkdyqRxypiJksBSqNjYr6YuJatwAgXTnE\n" + + "KMLL/J6oia5bPY4S6jKy/OsU1wkVGsDNG9W1FU5B1ZbjTg==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_4_Public_Primary_Certification_Authority_-_G2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDAjCCAmsCEDKIjprS9esTR/h/xCA3JfgwDQYJKoZIhvcNAQEFBQAwgcEx\n" + + "CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UE\n" + + "CxMzQ2xhc3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv\n" + + "cml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAt\n" + + "IEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBU\n" + + "cnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVow\n" + + "gcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoG\n" + + "A1UECxMzQ2xhc3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1\n" + + "dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5j\n" + + "LiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2ln\n" + + "biBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6\n" + + "8OTP+cSuhVS5B1f5j8V/aBH4xBewRNzjMHPVKmIquNDMHO0oW369atyzkSTK\n" + + "QWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDHqGKB3FtKqsGgtG7rL+VX\n" + + "xbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHwIDAQABMA0G\n" + + "CSqGSIb3DQEBBQUAA4GBAIWMEsGnuVAVess+rLhDityq3RS6iYF+ATwjcSGI\n" + + "L4LcY/oCRaxFWdcqWERbt5+BO5JoPeI3JPV7bI92NZYJqFmduc4jq3TWg/0y\n" + + "cyfYaT5DdPauxYma51N86Xv2S/PBZYPejYqcPIiNOVn8qj8ijaHBZlCBckzt\n" + + "ImRPT8qAkbYp\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_4_Public_Primary_Certification_Authority_-_G3.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHK\n" + + "MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNV\n" + + "BAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5\n" + + "IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBD\n" + + "BgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlm\n" + + "aWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3\n" + + "MTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24s\n" + + "IEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNV\n" + + "BAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQg\n" + + "dXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFBy\n" + + "aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI\n" + + "hvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1GQ9Wzsy1HyDkniYl\n" + + "S+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ+mGuqPKljYXC\n" + + "KtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0GbdU6LM8BDc\n" + + "VHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLmNxdL\n" + + "MEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY\n" + + "ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDD\n" + + "Zq3/ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1Wr\n" + + "IhVZPMq1CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXtt\n" + + "mhwwjIDLk5Mqg6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csK\n" + + "vE+MW8VLADsfKoKmfjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluP\n" + + "QSjA1egtTaRezarZ7c7c2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kP\n" + + "mF6Z6PDQpLv1U70qzlmwr25/bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr\n" + + "9Xgn2uf3ZkPznoM+IKrDNWCRzg==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_RSA_Secure_Server_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICNDCCAaECEAKtZn5ORf5eV288mBle3cAwDQYJKoZIhvcNAQECBQAwXzEL\n" + + "MAkGA1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMu\n" + + "MS4wLAYDVQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9y\n" + + "aXR5MB4XDTk0MTEwOTAwMDAwMFoXDTEwMDEwNzIzNTk1OVowXzELMAkGA1UE\n" + + "BhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYD\n" + + "VQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGb\n" + + "MA0GCSqGSIb3DQEBAQUAA4GJADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6O\n" + + "LDfO6zV4ZFQD5YRAUcm/jwjiioII0haGN1XpsSECrXZogZoFokvJSyVmIlZs\n" + + "iAeP94FZbYQHZXATcXY+m3dM41CJVphIuR2nKRoTLkoRWZweFdVJVCxzOmmC\n" + + "sZc5nG1wZ0jl3S3WyB57AgMBAAEwDQYJKoZIhvcNAQECBQADfgBl3X7hsuyw\n" + + "4jrg7HFGmhkRuNPHoLQDQCYCPgmc4RKz0Vr2N6W3YQO2WxZpO8ZECAyIUwxr\n" + + "l0nHPjXcbLm7qt9cuzovk2C2qUtN8iD3zV9/ZHuO3ABc1/p3yjkWWW8O6tO1\n" + + "g39NTUJWdrTJXwT4OPjr0l91X817/OWOgHz8UA==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Secure_Server_OCSP_Responder.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDnzCCAwygAwIBAgIRAP9F1SddJPuzwjkkU1fhT94wDQYJKoZIhvcNAQEF\n" + + "BQAwXzELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5\n" + + "LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24g\n" + + "QXV0aG9yaXR5MB4XDTAwMDgwNDAwMDAwMFoXDTA0MDgwMzIzNTk1OVowgZ4x\n" + + "FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU\n" + + "cnVzdCBOZXR3b3JrMTswOQYDVQQLEzJUZXJtcyBvZiB1c2UgYXQgaHR0cHM6\n" + + "Ly93d3cudmVyaXNpZ24uY29tL1JQQSAoYykwMDElMCMGA1UEAxMcU2VjdXJl\n" + + "IFNlcnZlciBPQ1NQIFJlc3BvbmRlcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAw\n" + + "gYkCgYEAuFGZZIUO7rMKaPC/Y3YdU/X8oXiMM+6f9L452psPTUepjyDoS0S9\n" + + "zs17kNEw6JDEJXuJKN699pMd/7n/krWpjeSuzOLDB4Nqo3IQASdiIqY1Jjkt\n" + + "ns9gDPxHpNfQQninHWzQy08VpykKtJVFxLHnWgnXOZXYHTWewr2zXcEMSx8C\n" + + "AwEAAaOCAR0wggEZMCAGA1UdEQQZMBekFTATMREwDwYDVQQDEwhPQ1NQIDEt\n" + + "NDA+BgNVHR8ENzA1MDOgMaAvhi1odHRwOi8vY3JsLnZlcmlzaWduLmNvbS9S\n" + + "U0FTZWN1cmVTZXJ2ZXItcC5jcmwwEwYDVR0lBAwwCgYIKwYBBQUHAwkwQgYI\n" + + "KwYBBQUHAQEENjA0MDIGCCsGAQUFBzABpiYWJGh0dHA6Ly9vY3NwLnZlcmlz\n" + + "aWduLmNvbS9vY3NwL3N0YXR1czBEBgNVHSAEPTA7MDkGC2CGSAGG+EUBBwEB\n" + + "MCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LnZlcmlzaWduLmNvbS9SUEEw\n" + + "CQYDVR0TBAIwADALBgNVHQ8EBAMCB4AwDQYJKoZIhvcNAQEFBQADfgAAsxBT\n" + + "ZpxJky4xoAJC0lhXfmah/huKYRhQQCweK0Gl1tv/rAgcWgVtAlwqtpZPR9u+\n" + + "TtvOzLqGuBjOsRKRX2P380g+zPFNE+RtCZR4AJLLoyCdBgtqoEMHztEZbI8Y\n" + + "dZqfFzP9qSa44+LewqjEWop/mNYHBmvMVp6GcM7U7w==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Time_Stamping_Authority_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDzTCCAzagAwIBAgIQU2GyYK7bcY6nlLMTM/QHCTANBgkqhkiG9w0BAQUF\n" + + "ADCBwTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTww\n" + + "OgYDVQQLEzNDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24g\n" + + "QXV0aG9yaXR5IC0gRzIxOjA4BgNVBAsTMShjKSAxOTk4IFZlcmlTaWduLCBJ\n" + + "bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAsTFlZlcmlT\n" + + "aWduIFRydXN0IE5ldHdvcmswHhcNMDAwOTI2MDAwMDAwWhcNMTAwOTI1MjM1\n" + + "OTU5WjCBpTEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl\n" + + "cmlTaWduIFRydXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBh\n" + + "dCBodHRwczovL3d3dy52ZXJpc2lnbi5jb20vcnBhIChjKTAwMSwwKgYDVQQD\n" + + "EyNWZXJpU2lnbiBUaW1lIFN0YW1waW5nIEF1dGhvcml0eSBDQTCBnzANBgkq\n" + + "hkiG9w0BAQEFAAOBjQAwgYkCgYEA0hmdZ8IAIVlizrQJIkRpivglWtvtDbc2\n" + + "fk7gu5Q+kCWHwmFHKdm9VLhjzCx9abQzNvQ3B5rB3UBU/OB4naCTuQk9I1F/\n" + + "RMIUdNsKvsvJMDRAmD7Q1yUQgZS9B0+c1lQn3y6ov8uQjI11S7zi6ESHzeZB\n" + + "CiVu6PQkAsVSD27smHUCAwEAAaOB3zCB3DAPBgNVHRMECDAGAQH/AgEAMEUG\n" + + "A1UdIAQ+MDwwOgYMYIZIAYb4RQEHFwEDMCowKAYIKwYBBQUHAgEWHGh0dHBz\n" + + "Oi8vd3d3LnZlcmlzaWduLmNvbS9ycGEwMQYDVR0fBCowKDAmoCSgIoYgaHR0\n" + + "cDovL2NybC52ZXJpc2lnbi5jb20vcGNhMy5jcmwwCwYDVR0PBAQDAgEGMEIG\n" + + "CCsGAQUFBwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJp\n" + + "c2lnbi5jb20vb2NzcC9zdGF0dXMwDQYJKoZIhvcNAQEFBQADgYEAgnBold+2\n" + + "DcIBcBlK0lRWHqzyRUyHuPU163hLBanInTsZIS5wNEqi9YngFXVF5yg3ADQn\n" + + "Keg3S/LvRJdrF1Eaw1adPBqK9kpGRjeM+sv1ZFo4aC4cw+9wzrhGBha/937n\n" + + "tag+RaypJXUie28/sJyU58dzq6wf7iWbwBbtt8pb8BQ=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Visa_International_Global_Root_2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDgDCCAmigAwIBAgICAx4wDQYJKoZIhvcNAQEFBQAwYTELMAkGA1UEBhMC\n" + + "VVMxDTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25h\n" + + "bCBTZXJ2aWNlIEFzc29jaWF0aW9uMRIwEAYDVQQDEwlHUCBSb290IDIwHhcN\n" + + "MDAwODE2MjI1MTAwWhcNMjAwODE1MjM1OTAwWjBhMQswCQYDVQQGEwJVUzEN\n" + + "MAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNl\n" + + "cnZpY2UgQXNzb2NpYXRpb24xEjAQBgNVBAMTCUdQIFJvb3QgMjCCASIwDQYJ\n" + + "KoZIhvcNAQEBBQADggEPADCCAQoCggEBAKkBcLWqxEDwq2omYXkZAPy/mzdZ\n" + + "DK9vZBv42pWUJGkzEXDK41Z0ohdXZFwgBuHW73G3O/erwWnQSaSxBNf0V2KJ\n" + + "XLB1LRckaeNCYOTudNargFbYiCjh+20i/SN8RnNPflRzHqgsVVh1t0zzWkWl\n" + + "Ahr62p3DRcMiXvOL8WAp0sdftAw6UYPvMPjU58fy+pmjIlC++QU3o63tmsPm\n" + + "7IgbthknGziLgE3sucfFicv8GjLtI/C1AVj59o/ghalMCXI5Etuz9c9OYmTa\n" + + "xhkVOmMd6RdVoUwiPDQyRvhlV7or7zaMavrZ2UT0qt2E1w0cslSsMoW0ZA3e\n" + + "QbuxNMYBhjJk1Z8CAwEAAaNCMEAwHQYDVR0OBBYEFJ59SzS/ca3CBfYDdYDO\n" + + "qU8axCRMMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqG\n" + + "SIb3DQEBBQUAA4IBAQAhpXYUVfmtJ3CPPPTVbMjMCqujmAuKBiPFyWHbmQdp\n" + + "NSYx/scuhMKZYdQN6X0uEyt8joW2hcdLzzW2LEc9zikv2G+fiRxkk78IvXbQ\n" + + "kIqUs38oW26sTTMs7WXcFsziza6kPWKSBpUmv9+55CCmc2rBvveURNZNbyoL\n" + + "axhNdBA2aGpawWqn3TYpjLgwi08hPwAuVDAHOrqK5MOeyti12HvOdUVmB/Rt\n" + + "Ldh6yumJivIj2C/LbgA2T/vwLwHMD8AiZfSr4k5hLQOCfZEWtTDVFN5ex5D8\n" + + "ofyrEK9ca3CnB+8phuiyJccg/ybdd+95RBTEvd07xQObdyPsoOy7Wjm1zK0G\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Visa_eCommerce_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUF\n" + + "ADBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlz\n" + + "YSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMT\n" + + "E1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0\n" + + "MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UE\n" + + "CxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAa\n" + + "BgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA\n" + + "A4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh\n" + + "28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8bRaVK7362\n" + + "rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81\n" + + "q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtF\n" + + "Wsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0\n" + + "lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaLdXe6YJ2E5/4t\n" + + "AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G\n" + + "A1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOC\n" + + "AQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR\n" + + "zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKht\n" + + "cbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGI\n" + + "xHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu\n" + + "YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/\n" + + "hC3euiInlhBx6yLt398znM/jra6O1I7mT1GvFpLgXPYHDw==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // beTRUSTed_Root_CA-Baltimore_Implementation.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIFajCCBFKgAwIBAgIEPLU9RjANBgkqhkiG9w0BAQUFADBmMRIwEAYDVQQK\n" + + "EwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEzMDEG\n" + + "A1UEAxMqYmVUUlVTVGVkIFJvb3QgQ0EtQmFsdGltb3JlIEltcGxlbWVudGF0\n" + + "aW9uMB4XDTAyMDQxMTA3Mzg1MVoXDTIyMDQxMTA3Mzg1MVowZjESMBAGA1UE\n" + + "ChMJYmVUUlVTVGVkMRswGQYDVQQLExJiZVRSVVNUZWQgUm9vdCBDQXMxMzAx\n" + + "BgNVBAMTKmJlVFJVU1RlZCBSb290IENBLUJhbHRpbW9yZSBJbXBsZW1lbnRh\n" + + "dGlvbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALx+xDmcjOPW\n" + + "HIb/ymKt4H8wRXqOGrO4x/nRNv8i805qX4QQ+2aBw5R5MdKR4XeOGCrDFN5R\n" + + "9U+jK7wYFuK13XneIviCfsuBH/0nLI/6l2Qijvj/YaOcGx6Sj8CoCd8JEey3\n" + + "fTGaGuqDIQY8n7pc/5TqarjDa1U0Tz0yH92BFODEPM2dMPgwqZfT7syj0B9f\n" + + "HBOB1BirlNFjw55/NZKeX0Tq7PQiXLfoPX2k+YmpkbIq2eszh+6l/ePazIjm\n" + + "iSZuxyuC0F6dWdsU7JGDBcNeDsYq0ATdcT0gTlgn/FP7eHgZFLL8kFKJOGJg\n" + + "B7Sg7KxrUNb9uShr71ItOrL/8QFArDcCAwEAAaOCAh4wggIaMA8GA1UdEwEB\n" + + "/wQFMAMBAf8wggG1BgNVHSAEggGsMIIBqDCCAaQGDysGAQQBsT4AAAEJKIOR\n" + + "MTCCAY8wggFIBggrBgEFBQcCAjCCAToaggE2UmVsaWFuY2Ugb24gb3IgdXNl\n" + + "IG9mIHRoaXMgQ2VydGlmaWNhdGUgY3JlYXRlcyBhbiBhY2tub3dsZWRnbWVu\n" + + "dCBhbmQgYWNjZXB0YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5k\n" + + "YXJkIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHVzZSwgdGhlIENlcnRpZmlj\n" + + "YXRpb24gUHJhY3RpY2UgU3RhdGVtZW50IGFuZCB0aGUgUmVseWluZyBQYXJ0\n" + + "eSBBZ3JlZW1lbnQsIHdoaWNoIGNhbiBiZSBmb3VuZCBhdCB0aGUgYmVUUlVT\n" + + "VGVkIHdlYiBzaXRlLCBodHRwOi8vd3d3LmJldHJ1c3RlZC5jb20vcHJvZHVj\n" + + "dHNfc2VydmljZXMvaW5kZXguaHRtbDBBBggrBgEFBQcCARY1aHR0cDovL3d3\n" + + "dy5iZXRydXN0ZWQuY29tL3Byb2R1Y3RzX3NlcnZpY2VzL2luZGV4Lmh0bWww\n" + + "HQYDVR0OBBYEFEU9w6nR3D8kVpgccxiIav+DR+22MB8GA1UdIwQYMBaAFEU9\n" + + "w6nR3D8kVpgccxiIav+DR+22MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0B\n" + + "AQUFAAOCAQEASZK8o+6svfoNyYt5hhwjdrCAWXf82n+0S9/DZEtqTg6t8n1Z\n" + + "dwWtColzsPq8y9yNAIiPpqCy6qxSJ7+hSHyXEHu67RMdmgduyzFiEuhjA6p9\n" + + "beP4G3YheBufS0OM00mG9htc9i5gFdPp43t1P9ACg9AYgkHNZTfqjjJ+vWuZ\n" + + "XTARyNtIVBw74acT02pIk/c9jH8F6M7ziCpjBLjqflh8AXtb4cV97yHgjQ5d\n" + + "UX2xZ/2jvTg2xvI4hocalmhgRvsoFEdV4aeADGvi6t9NfJBIoDa9CReJf8Py\n" + + "05yc493EG931t3GzUwWJBtDLSoDByFOQtTwxiBdQn8nEDovYqAJjDQ==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // beTRUSTed_Root_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIFLDCCBBSgAwIBAgIEOU99hzANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQG\n" + + "EwJXVzESMBAGA1UEChMJYmVUUlVTVGVkMRswGQYDVQQDExJiZVRSVVNUZWQg\n" + + "Um9vdCBDQXMxGjAYBgNVBAMTEWJlVFJVU1RlZCBSb290IENBMB4XDTAwMDYy\n" + + "MDE0MjEwNFoXDTEwMDYyMDEzMjEwNFowWjELMAkGA1UEBhMCV1cxEjAQBgNV\n" + + "BAoTCWJlVFJVU1RlZDEbMBkGA1UEAxMSYmVUUlVTVGVkIFJvb3QgQ0FzMRow\n" + + "GAYDVQQDExFiZVRSVVNUZWQgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD\n" + + "ggEPADCCAQoCggEBANS0c3oTCjhVAb6JVuGUntS+WutKNHUbYSnE4a0IYCF4\n" + + "SP+00PpeQY1hRIfo7clY+vyTmt9P6j41ffgzeubx181vSUs9Ty1uDoM6GHh3\n" + + "o8/n9E1z2Jo7Gh2+lVPPIJfCzz4kUmwMjmVZxXH/YgmPqsWPzGCgc0rXOD8V\n" + + "cr+il7dw6K/ifhYGTPWqZCZyByWtNfwYsSbX2P8ZDoMbjNx4RWc0PfSvHI3k\n" + + "bWvtILNnmrRhyxdviTX/507AMhLn7uzf/5cwdO2NR47rtMNE5qdMf1ZD6Li8\n" + + "tr76g5fmu/vEtpO+GRg+jIG5c4gW9JZDnGdzF5DYCW5jrEq2I8QBoa2k5MUC\n" + + "AwEAAaOCAfgwggH0MA8GA1UdEwEB/wQFMAMBAf8wggFZBgNVHSAEggFQMIIB\n" + + "TDCCAUgGCisGAQQBsT4BAAAwggE4MIIBAQYIKwYBBQUHAgIwgfQagfFSZWxp\n" + + "YW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVz\n" + + "IGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0\n" + + "ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGFuZCBjZXJ0aWZpY2F0aW9u\n" + + "IHByYWN0aWNlIHN0YXRlbWVudCwgd2hpY2ggY2FuIGJlIGZvdW5kIGF0IGJl\n" + + "VFJVU1RlZCdzIHdlYiBzaXRlLCBodHRwczovL3d3dy5iZVRSVVNUZWQuY29t\n" + + "L3ZhdWx0L3Rlcm1zMDEGCCsGAQUFBwIBFiVodHRwczovL3d3dy5iZVRSVVNU\n" + + "ZWQuY29tL3ZhdWx0L3Rlcm1zMDQGA1UdHwQtMCswKaAnoCWkIzAhMRIwEAYD\n" + + "VQQKEwliZVRSVVNUZWQxCzAJBgNVBAYTAldXMB0GA1UdDgQWBBQquZtpLjub\n" + + "2M3eKjEENGvKBxirZzAfBgNVHSMEGDAWgBQquZtpLjub2M3eKjEENGvKBxir\n" + + "ZzAOBgNVHQ8BAf8EBAMCAf4wDQYJKoZIhvcNAQEFBQADggEBAHlh26Nebhax\n" + + "6nZR+csVm8tpvuaBa58oH2U+3RGFktToQb9+M70j5/Egv6S0phkBxoyNNXxl\n" + + "pE8JpNbYIxUFE6dDea/bow6be3ga8wSGWsb2jCBHOElQBp1yZzrwmAOtlmdE\n" + + "/D8QDYZN5AA7KXvOOzuZhmElQITcE2K3+spZ1gMe1lMBzW1MaFVA4e5rxyoA\n" + + "AEiCswoBw2AqDPeCNe5IhpbkdNQ96gFxugR1QKepfzk5mlWXKWWuGVUlBXJH\n" + + "0+gY3Ljpr0NzARJ0o+FcXxVdJPP55PS2Z2cS52QiivalQaYctmBjRYoQtLpG\n" + + "EK5BV2VsPyMQPyEQWbfkQN0mDCP2qq4=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // beTRUSTed_Root_CA_-_Entrust_Implementation.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIGUTCCBTmgAwIBAgIEPLVPQDANBgkqhkiG9w0BAQUFADBmMRIwEAYDVQQK\n" + + "EwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEzMDEG\n" + + "A1UEAxMqYmVUUlVTVGVkIFJvb3QgQ0EgLSBFbnRydXN0IEltcGxlbWVudGF0\n" + + "aW9uMB4XDTAyMDQxMTA4MjQyN1oXDTIyMDQxMTA4NTQyN1owZjESMBAGA1UE\n" + + "ChMJYmVUUlVTVGVkMRswGQYDVQQLExJiZVRSVVNUZWQgUm9vdCBDQXMxMzAx\n" + + "BgNVBAMTKmJlVFJVU1RlZCBSb290IENBIC0gRW50cnVzdCBJbXBsZW1lbnRh\n" + + "dGlvbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALr0RAOqEmq1\n" + + "Q+xVkrYwfTVXDNvzDSduTPdQqJtOK2/b9a0cS12zqcH+e0TrW6MFDR/FNCsw\n" + + "ACnxeECypP869AGIF37m1CbTukzqMvtDd5eHI8XbQ6P1KqNRXuE70mVpflUV\n" + + "m3rnafdE4Fe1FehmYA8NA/uCjqPoEXtsvsdjDheT389Lrm5zdeDzqrmkwAkb\n" + + "hepxKYhBMvnwKg5sCfJ0a2ZsUhMfGLzUPvfYbiCeyv78IZTuEyhL11xeDGbu\n" + + "6bsPwTSxfwh28z0mcMmLJR1iJAzqHHVOwBLkuhMdMCktVjMFu5dZfsZJT4nX\n" + + "LySotohAtWSSU1Yk5KKghbNekLQSM80CAwEAAaOCAwUwggMBMIIBtwYDVR0g\n" + + "BIIBrjCCAaowggGmBg8rBgEEAbE+AAACCSiDkTEwggGRMIIBSQYIKwYBBQUH\n" + + "AgIwggE7GoIBN1JlbGlhbmNlIG9uIG9yIHVzZSBvZiB0aGlzIENlcnRpZmlj\n" + + "YXRlIGNyZWF0ZXMgYW4gYWNrbm93bGVkZ21lbnQgYW5kIGFjY2VwdGFuY2Ug\n" + + "b2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29u\n" + + "ZGl0aW9ucyBvZiB1c2UsIHRoZSBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0\n" + + "YXRlbWVudCBhbmQgdGhlIFJlbHlpbmcgUGFydHkgQWdyZWVtZW50LCB3aGlj\n" + + "aCBjYW4gYmUgZm91bmQgYXQgdGhlIGJlVFJVU1RlZCB3ZWIgc2l0ZSwgaHR0\n" + + "cHM6Ly93d3cuYmV0cnVzdGVkLmNvbS9wcm9kdWN0c19zZXJ2aWNlcy9pbmRl\n" + + "eC5odG1sMEIGCCsGAQUFBwIBFjZodHRwczovL3d3dy5iZXRydXN0ZWQuY29t\n" + + "L3Byb2R1Y3RzX3NlcnZpY2VzL2luZGV4Lmh0bWwwEQYJYIZIAYb4QgEBBAQD\n" + + "AgAHMIGJBgNVHR8EgYEwfzB9oHugeaR3MHUxEjAQBgNVBAoTCWJlVFJVU1Rl\n" + + "ZDEbMBkGA1UECxMSYmVUUlVTVGVkIFJvb3QgQ0FzMTMwMQYDVQQDEypiZVRS\n" + + "VVNUZWQgUm9vdCBDQSAtIEVudHJ1c3QgSW1wbGVtZW50YXRpb24xDTALBgNV\n" + + "BAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMjA0MTEwODI0MjdagQ8yMDIyMDQx\n" + + "MTA4NTQyN1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFH1w5a44iwY/qhwa\n" + + "j/nPJDCqhIQWMB0GA1UdDgQWBBR9cOWuOIsGP6ocGo/5zyQwqoSEFjAMBgNV\n" + + "HRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIEkDANBgkq\n" + + "hkiG9w0BAQUFAAOCAQEAKrgXzh8QlOu4mre5X+za95IkrNySO8cgjfKZ5V04\n" + + "ocI07cUTWVwFtStPYZuR+0H8/NU8TZh2BvWBfevdkObRVlTa4y0MnxEylCIB\n" + + "evZsLHRnBMylj44ss0O1lKLQfelifwa+JwGDnjr9iu6YQ0pr17WXOzq/T220\n" + + "Y/ozADQuLW2WyXvKmWO6vvT2MKAtmJbpVkQFqUSjYRDrgqFnXbxdJ3Wqiig2\n" + + "KjiS2d2kXgClzMx8KSreKJCrt+G2/30lC0DYqjSjLd4H61/OCt3Kfjp9JsFi\n" + + "aDrmLzfzgYYhxKlkqu9FNtEaZnz46TfW1mG+oq1I59/mdP7TbX3SJdysYlep\n" + + "9w==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // beTRUSTed_Root_CA_-_RSA_Implementation.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIFaDCCBFCgAwIBAgIQO1nHe81bV569N1KsdrSqGjANBgkqhkiG9w0BAQUF\n" + + "ADBiMRIwEAYDVQQKEwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBS\n" + + "b290IENBczEvMC0GA1UEAxMmYmVUUlVTVGVkIFJvb3QgQ0EgLSBSU0EgSW1w\n" + + "bGVtZW50YXRpb24wHhcNMDIwNDExMTExODEzWhcNMjIwNDEyMTEwNzI1WjBi\n" + + "MRIwEAYDVQQKEwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290\n" + + "IENBczEvMC0GA1UEAxMmYmVUUlVTVGVkIFJvb3QgQ0EgLSBSU0EgSW1wbGVt\n" + + "ZW50YXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkujQw\n" + + "CY5X0LkGLG9uJIAiv11DpvpPrILnHGhwhRujbrWqeNluB0s/6d/16uhUoWGK\n" + + "Di9pdRi3DOUUjXFumLhV/AyV0Jtu4S2I1DpAa5LxmZZk3tv/ePTulh1HiXzU\n" + + "vrmIdyM6CeYEnm2qXtLIvZpOGd+J6lsOfsPktPDgaTuID0GQ+NRxQyTBjyZL\n" + + "O1bp/4xsN+lFrYWMU8NghpBKlsmzVLC7F/AcRdnUGxlkVgoZ98zh/4avflhe\n" + + "rHqQH8koOUV7orbHnB/ahdQhhlkwk75TMzf270HPM8ercmsl9fNTGwxMLvF1\n" + + "S++gh/f+ihXQbNXL+WhTuXAVE8L1LvtDNXUtAgMBAAGjggIYMIICFDAMBgNV\n" + + "HRMEBTADAQH/MIIBtQYDVR0gBIIBrDCCAagwggGkBg8rBgEEAbE+AAADCSiD\n" + + "kTEwggGPMEEGCCsGAQUFBwIBFjVodHRwOi8vd3d3LmJldHJ1c3RlZC5jb20v\n" + + "cHJvZHVjdHNfc2VydmljZXMvaW5kZXguaHRtbDCCAUgGCCsGAQUFBwICMIIB\n" + + "OhqCATZSZWxpYW5jZSBvbiBvciB1c2Ugb2YgdGhpcyBDZXJ0aWZpY2F0ZSBj\n" + + "cmVhdGVzIGFuIGFja25vd2xlZGdtZW50IGFuZCBhY2NlcHRhbmNlIG9mIHRo\n" + + "ZSB0aGVuIGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5kIGNvbmRpdGlv\n" + + "bnMgb2YgdXNlLCB0aGUgQ2VydGlmaWNhdGlvbiBQcmFjdGljZSBTdGF0ZW1l\n" + + "bnQgYW5kIHRoZSBSZWx5aW5nIFBhcnR5IEFncmVlbWVudCwgd2hpY2ggY2Fu\n" + + "IGJlIGZvdW5kIGF0IHRoZSBiZVRSVVNUZWQgd2ViIHNpdGUsIGh0dHA6Ly93\n" + + "d3cuYmV0cnVzdGVkLmNvbS9wcm9kdWN0c19zZXJ2aWNlcy9pbmRleC5odG1s\n" + + "MAsGA1UdDwQEAwIBBjAfBgNVHSMEGDAWgBSp7BR++dlDzFMrFK3P9/BZiUHN\n" + + "GTAdBgNVHQ4EFgQUqewUfvnZQ8xTKxStz/fwWYlBzRkwDQYJKoZIhvcNAQEF\n" + + "BQADggEBANuXsHXqDMTBmMpWBcCorSZIry0g6IHHtt9DwSwddUvUQo3neqh0\n" + + "3GZCWYez9Wlt2ames30cMcH1VOJZJEnl7r05pmuKmET7m9cqg5c0Lcd9NUwt\n" + + "NLg+DcTsiCevnpL9UGGCqGAHFFPMZRPB9kdEadIxyKbdLrML3kqNWz2rDcI1\n" + + "UqJWN8wyiyiFQpyRQHpwKzg21eFzGh/l+n5f3NacOzDq28BbJ1zTcwfBwvNM\n" + + "m2+fG8oeqqg4MwlYsq78B+g23FW6L09A/nq9BqaBwZMifIYRCgZ3SK41ty8y\n" + + "mmFei74pnykkiFY5LKjSq5YDWtRIn7lAhAuYaPsBQ9Yb4gmxlxw=\n" + + "-----END CERTIFICATE-----\n"); + + CA_CERTS = new StaticTrustAnchors((X509Certificate[]) certs.toArray(new X509Certificate[0])); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/AbstractHandshake.java b/libjava/classpath/gnu/javax/net/ssl/provider/AbstractHandshake.java new file mode 100644 index 000000000..bf03ed77f --- /dev/null +++ b/libjava/classpath/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); + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Alert.java b/libjava/classpath/gnu/javax/net/ssl/provider/Alert.java new file mode 100644 index 000000000..0ceb96bbb --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Alert.java @@ -0,0 +1,288 @@ +/* Alert.java -- SSL Alert message. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.PrintWriter; +import java.io.StringWriter; + +import java.nio.ByteBuffer; + +/** + * An alert message in the SSL protocol. Alerts are sent both as warnings + * which may allow execution to continue, or they may be fatal, which will + * halt this session. An alert object is composed of two enums -- the level, + * which indicates the seriousness of the alert, and the description, which + * indicates the reason for the alert. + * + *
+ * struct {
+ *   AlertLevel       level;
+ *   AlertDescription description;
+ * }
+ * 
+ */ +public final class Alert implements Constructed +{ + + // Fields. + // ------------------------------------------------------------------------- + + /** The underlying byte buffer. */ + private final ByteBuffer buffer; + + // Constructor. + // ------------------------------------------------------------------------- + + public Alert (final ByteBuffer buffer) + { + this.buffer = buffer; + } + + public Alert (final Level level, final Description description) + { + level.getClass (); + description.getClass (); + ByteBuffer b = ByteBuffer.allocate (2); + b.put (0, (byte) level.getValue ()); + b.put (1, (byte) description.getValue ()); + this.buffer = b.asReadOnlyBuffer (); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public int length () + { + return 2; + } + + byte[] getEncoded() + { + byte[] buf = new byte[2]; + buffer.position (0); + buffer.get (buf); + return buf; + } + + public Level level() + { + return Level.forInteger (buffer.get (0) & 0xFF); + } + + public Description description() + { + return Description.forInteger (buffer.get (1) & 0xFF); + } + + public void setLevel (final Level level) + { + buffer.put (0, (byte) level.getValue ()); + } + + public void setDescription (final Description description) + { + buffer.put (1, (byte) description.getValue ()); + } + + public boolean equals (Object o) + { + if (!(o instanceof Alert)) + return false; + Alert that = (Alert) o; + return that.buffer.position (0).equals (buffer.position (0)); + } + + public int hashCode () + { + return buffer.getShort (0) & 0xFFFF; + } + + public String toString() + { + return toString (null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter (); + PrintWriter out = new PrintWriter (str); + if (prefix != null) out.print (prefix); + out.println ("struct {"); + if (prefix != null) out.print (prefix); + out.print (" level: "); + out.print (level ()); + out.println (";"); + if (prefix != null) out.print (prefix); + out.print (" description: "); + out.print (description ()); + out.println (";"); + if (prefix != null) out.print (prefix); + out.print ("} Alert;"); + return str.toString (); + } + + // Enumerations. + // ------------------------------------------------------------------------- + + /** + * The level enumeration. + * + *
+   * enum { warning(1), fatal(2), (255) } AlertLevel;
+   * 
+ */ + public static enum Level + { + + WARNING (1), FATAL (2); + + private final int value; + + private Level(int value) + { + this.value = value; + } + + public static Level forInteger (final int value) + { + switch (value & 0xFF) + { + case 1: return WARNING; + case 2: return FATAL; + default: throw new IllegalArgumentException ("invalid alert level: " + value); + } + } + + public int getValue() + { + return value; + } + } + + /** + * The description enumeration. + */ + public static enum Description + { + CLOSE_NOTIFY ( 0), + UNEXPECTED_MESSAGE ( 10), + BAD_RECORD_MAC ( 20), + DECRYPTION_FAILED ( 21), + RECORD_OVERFLOW ( 22), + DECOMPRESSION_FAILURE ( 30), + HANDSHAKE_FAILURE ( 40), + NO_CERTIFICATE ( 41), + BAD_CERTIFICATE ( 42), + UNSUPPORTED_CERTIFICATE ( 43), + CERTIFICATE_REVOKED ( 44), + CERTIFICATE_EXPIRED ( 45), + CERTIFICATE_UNKNOWN ( 46), + ILLEGAL_PARAMETER ( 47), + UNKNOWN_CA ( 48), + ACCESS_DENIED ( 49), + DECODE_ERROR ( 50), + DECRYPT_ERROR ( 51), + EXPORT_RESTRICTION ( 60), + PROTOCOL_VERSION ( 70), + INSUFFICIENT_SECURITY ( 71), + INTERNAL_ERROR ( 80), + USER_CANCELED ( 90), + NO_RENEGOTIATION (100), + UNSUPPORTED_EXTENSION (110), + CERTIFICATE_UNOBTAINABLE (111), + UNRECOGNIZED_NAME (112), + BAD_CERTIFICATE_STATUS_RESPONSE (113), + BAD_CERTIFICATE_HASH_VALUE (114), + UNKNOWN_SRP_USERNAME (120), + MISSING_SRP_USERNAME (121); + + private final int value; + + private Description(int value) + { + this.value = value; + } + + /** + * Return an alert description object based on the specified integer + * value. + * + * @param value The raw description value. + * @return The appropriate description object. + */ + public static Description forInteger (final int value) + { + switch (value & 0xFF) + { + case 0: return CLOSE_NOTIFY; + case 10: return UNEXPECTED_MESSAGE; + case 20: return BAD_RECORD_MAC; + case 21: return DECRYPTION_FAILED; + case 22: return RECORD_OVERFLOW; + case 30: return DECOMPRESSION_FAILURE; + case 40: return HANDSHAKE_FAILURE; + case 41: return NO_CERTIFICATE; + case 42: return BAD_CERTIFICATE; + case 43: return UNSUPPORTED_CERTIFICATE; + case 44: return CERTIFICATE_REVOKED; + case 45: return CERTIFICATE_EXPIRED; + case 46: return CERTIFICATE_UNKNOWN; + case 47: return ILLEGAL_PARAMETER; + case 48: return UNKNOWN_CA; + case 49: return ACCESS_DENIED; + case 50: return DECODE_ERROR; + case 51: return DECRYPT_ERROR; + case 60: return EXPORT_RESTRICTION; + case 70: return PROTOCOL_VERSION; + case 71: return INSUFFICIENT_SECURITY; + case 80: return INTERNAL_ERROR; + case 90: return USER_CANCELED; + case 100: return NO_RENEGOTIATION; + case 120: return UNKNOWN_SRP_USERNAME; + case 121: return MISSING_SRP_USERNAME; + default: throw new IllegalArgumentException("unknown alert description: " + value); + } + } + + public int getValue() + { + return value; + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/AlertException.java b/libjava/classpath/gnu/javax/net/ssl/provider/AlertException.java new file mode 100644 index 000000000..90eaaf430 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/AlertException.java @@ -0,0 +1,101 @@ +/* AlertException.java -- exceptions generated by SSL alerts. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import javax.net.ssl.SSLException; + +/** + * An exception generated by an SSL alert. + */ +public class AlertException extends SSLException +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final Alert alert; + private final boolean isLocal; + + // Constructor. + // ------------------------------------------------------------------------- + + public AlertException(Alert alert, boolean isLocal) + { + super(alert.description().toString()); + this.alert = alert; + this.isLocal = isLocal; + } + + public AlertException(Alert alert) + { + this(alert, true); + } + + public AlertException(Alert alert, boolean isLocal, Throwable cause) + { + super(alert.description().toString(), cause); + this.alert = alert; + this.isLocal = isLocal; + } + + public AlertException(Alert alert, Throwable cause) + { + this(alert, true, cause); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String getMessage() + { + return alert.description() + ": " + + (isLocal ? "locally generated; " : "remotely generated; ") + + alert.level(); + } + + public Alert alert () + { + return alert; + } + + public boolean isLocal() + { + return isLocal; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Builder.java b/libjava/classpath/gnu/javax/net/ssl/provider/Builder.java new file mode 100644 index 000000000..070c51b76 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/Certificate.java b/libjava/classpath/gnu/javax/net/ssl/provider/Certificate.java new file mode 100644 index 000000000..68de1304d --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Certificate.java @@ -0,0 +1,177 @@ +/* Certificate.java -- SSL certificate message. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.ByteArrayInputStream; +import java.io.PrintWriter; +import java.io.StringWriter; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +/** + * The certificate object. This is used by both the client and the server + * to send their certificates (if any) to one another. + * + *

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. + // ------------------------------------------------------------------------- + + protected ByteBuffer buffer; + protected final CertificateType type; + + // Constructors. + // ------------------------------------------------------------------------- + + public Certificate (final ByteBuffer buffer, final CertificateType type) + { + buffer.getClass (); + type.getClass (); + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); + this.type = type; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public int length () + { + return (((buffer.get (0) & 0xFF) << 24) + | buffer.getShort (1)) + 3; + } + + public List certificates () + throws CertificateException, NoSuchAlgorithmException + { + 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); + } + return list; + } + + public String toString () + { + return toString (null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) + out.print (prefix); + out.println ("struct {"); + try + { + List certs = certificates (); + if (prefix != null) + out.print (prefix); + out.print (" certificateList: ["); + out.print (certs.size ()); + out.println ("] {"); + for (Iterator it = certs.iterator (); it.hasNext (); ) + { + java.security.cert.Certificate cert = + (java.security.cert.Certificate) it.next (); + if (prefix != null) + out.print (prefix); + out.print (" "); + if (cert instanceof X509Certificate) + out.print (((X509Certificate) cert).getSubjectDN ()); + else + out.print (cert); + out.println (";"); + } + if (prefix != null) + out.print (prefix); + out.println (" };"); + } + catch (CertificateException ce) + { + if (prefix != null) + out.print (prefix); + out.print (" "); + out.print (ce); + out.println (";"); + } + catch (NoSuchAlgorithmException nsae) + { + if (prefix != null) + out.print (prefix); + out.print (" "); + out.print (nsae); + out.println (";"); + } + out.print ("} Certificate;"); + return str.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateBuilder.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateBuilder.java new file mode 100644 index 000000000..1126e6fcc --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequest.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequest.java new file mode 100644 index 000000000..fd9d65be5 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequest.java @@ -0,0 +1,155 @@ +/* CertificateRequest.java -- SSL CertificateRequest message. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.PrintWriter; +import java.io.StringWriter; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * A request by the server for a client certificate. + * + *
+struct
+{
+  ClientCertificateType certificate_types<1..2^8-1>;
+  DistinguishedName certificate_authorities<3..2^16-1>;
+} CertificateRequest;
+
+ */ +public class CertificateRequest implements Handshake.Body +{ + + // Fields. + // ------------------------------------------------------------------------- + + protected ByteBuffer buffer; + + // Constructor. + // ------------------------------------------------------------------------- + + public CertificateRequest(final ByteBuffer buffer) + { + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public int length () + { + int o1 = (buffer.get (0) & 0xFF) + 1; + return o1 + (buffer.getShort (o1) & 0xFFFF) + 2; + } + + public ClientCertificateTypeList types () + { + return new ClientCertificateTypeList(buffer.duplicate()); + } + + public X500PrincipalList authorities () + { + int offset = (buffer.get (0) & 0xFF) + 1; + return new X500PrincipalList (((ByteBuffer) buffer.position(offset)).slice()); + } + + public String toString() + { + return toString (null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + String subprefix = " "; + if (prefix != null) subprefix = prefix + " "; + if (prefix != null) out.print (prefix); + out.println("struct {"); + if (prefix != null) out.print (prefix); + out.println (" types ="); + out.println (types ().toString (subprefix)); + if (prefix != null) out.print (prefix); + out.println(" authorities ="); + out.println (authorities ().toString (subprefix)); + if (prefix != null) out.print (prefix); + out.print ("} CertificateRequest;"); + return str.toString(); + } + + public static enum ClientCertificateType + { + RSA_SIGN (1), + DSS_SIGN (2), + RSA_FIXED_DH (3), + DSS_FIXED_DH (4); + + private final int value; + + // Constructor. + // ----------------------------------------------------------------------- + + private ClientCertificateType (final int value) + { + this.value = value; + } + + // Class method. + // ----------------------------------------------------------------------- + + static ClientCertificateType forValue (final int value) + { + switch (value) + { + case 1: return RSA_SIGN; + case 2: return DSS_SIGN; + case 3: return RSA_FIXED_DH; + case 4: return DSS_FIXED_DH; + default: throw new IllegalArgumentException("unknown client certificate type: " + value); + } + } + + public int getValue() + { + return value; + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequestBuilder.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequestBuilder.java new file mode 100644 index 000000000..f32c52acf --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequestBuilder.java @@ -0,0 +1,111 @@ +/* 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 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/libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusRequest.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusRequest.java new file mode 100644 index 000000000..e66373620 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusType.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusType.java new file mode 100644 index 000000000..0d52b2778 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/CertificateType.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateType.java new file mode 100644 index 000000000..ecba21b63 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateType.java @@ -0,0 +1,62 @@ +/* CertificateType.java -- the certificate type extension. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +public enum CertificateType +{ + X509 (0), + OPEN_PGP (1); + + private final int value; + + private CertificateType(int value) + { + this.value = value; + } + + public static CertificateType forValue (final int value) + { + switch (value) + { + case 0: return X509; + case 1: return OPEN_PGP; + default: throw new IllegalArgumentException ("unknown certificate type: " + value); + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateURL.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateURL.java new file mode 100644 index 000000000..737efcacd --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/CertificateVerify.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateVerify.java new file mode 100644 index 000000000..dfa5f6028 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateVerify.java @@ -0,0 +1,83 @@ +/* CertificateVerify.java -- SSL CertificateVerify message. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.ByteBuffer; + +public class CertificateVerify extends Signature implements Handshake.Body +{ + + // Contstructor. + // ------------------------------------------------------------------------- + + public CertificateVerify(final ByteBuffer buffer, final SignatureAlgorithm sigAlg) + { + super(buffer, sigAlg); + } + + public CertificateVerify(final byte[] sigVal, final SignatureAlgorithm sigAlg) + { + super(sigVal, sigAlg); + } + + // Instance method. + // ------------------------------------------------------------------------- + + public String toString() + { + return toString (null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter (); + PrintWriter out = new PrintWriter (str); + if (prefix != null) out.print (prefix); + out.println("struct {"); + String subprefix = " "; + if (prefix != null) + subprefix = prefix + subprefix; + out.println (super.toString (subprefix)); + if (prefix != null) out.print (prefix); + out.print ("} CertificateVerify;"); + return str.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CipherAlgorithm.java b/libjava/classpath/gnu/javax/net/ssl/provider/CipherAlgorithm.java new file mode 100644 index 000000000..98e05af31 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/CipherSuite.java b/libjava/classpath/gnu/javax/net/ssl/provider/CipherSuite.java new file mode 100644 index 000000000..1c5923129 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/CipherSuite.java @@ -0,0 +1,837 @@ +/* CipherSuite.java -- Supported cipher suites. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import gnu.java.security.action.GetSecurityPropertyAction; + +import java.io.IOException; +import java.io.OutputStream; + +import java.nio.ByteBuffer; + +import java.security.AccessController; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; + +import javax.crypto.Cipher; +import javax.crypto.Mac; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.NullCipher; + +public final class CipherSuite implements Constructed +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + private static final List 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. + public static final CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.RSA, + SignatureAlgorithm.RSA, + MacAlgorithm.SHA, 16, 0x00, 0x2F, + "TLS_RSA_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_DH_DSS_WITH_AES_128_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.DH_DSS, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 16, 0x00, 0x30, + "TLS_DH_DSS_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_DH_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.DH_RSA, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 16, 0x00, 0x31, + "TLS_DH_RSA_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.DHE_DSS, true, + SignatureAlgorithm.DSA, + MacAlgorithm.SHA, 16, 0x00, 0x32, + "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.DHE_RSA, true, + SignatureAlgorithm.RSA, + MacAlgorithm.SHA, 16, 0x00, 0x33, + "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.RSA, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 32, 0x00, 0x35, + "TLS_RSA_WITH_AES_256_CBC_SHA"); + public static final CipherSuite TLS_DH_DSS_WITH_AES_256_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.DH_DSS, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 32, 0x00, 0x36, + "TLS_DH_DSS_WITH_AES_256_CBC_SHA"); + public static final CipherSuite TLS_DH_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.DH_RSA, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 32, 0x00, 0x37, + "TLS_DH_RSA_WITH_AES_256_CBC_SHA"); + public static final CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.DHE_DSS, true, + SignatureAlgorithm.DSA, + MacAlgorithm.SHA, 32, 0x00, 0x38, + "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"); + public static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.DHE_RSA, true, + SignatureAlgorithm.RSA, + MacAlgorithm.SHA, 32, 0x00, 0x39, + "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"); + + // Secure remote password (SRP) ciphersuites + // Actual ID values are TBD, so these are omitted until they are specified. + /*public static final CipherSuite TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite (CipherAlgorithm.DESede, + KeyExchangeAlgorithm.SRP, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 24, 0x00, 0x50, + "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite (CipherAlgorithm.DESede, + KeyExchangeAlgorithm.SRP, + SignatureAlgorithm.RSA, + MacAlgorithm.SHA, 24, 0x00, 0x51, + "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA = + new CipherSuite (CipherAlgorithm.DESede, + KeyExchangeAlgorithm.SRP, + SignatureAlgorithm.DSA, + MacAlgorithm.SHA, 24, 0x00, 0x52, + "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_SRP_SHA_WITH_AES_128_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.SRP, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 16, 0x00, 0x53, + "TLS_SRP_SHA_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.SRP, + SignatureAlgorithm.RSA, + MacAlgorithm.SHA, 16, 0x00, 0x54, + "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.SRP, + SignatureAlgorithm.DSA, + MacAlgorithm.SHA, 16, 0x00, 0x55, + "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_SRP_SHA_WITH_AES_256_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.SRP, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 32, 0x00, 0x56, + "TLS_SRP_SHA_WITH_AES_256_CBC_SHA"); + public static final CipherSuite TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.SRP, + SignatureAlgorithm.RSA, + MacAlgorithm.SHA, 32, 0x00, 0x57, + "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA"); + public static final CipherSuite TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.SRP, + SignatureAlgorithm.DSA, + MacAlgorithm.SHA, 32, 0x00, 0x58, + "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA");*/ + + // Pre-shared key suites. + public static final CipherSuite TLS_PSK_WITH_RC4_128_SHA = + new CipherSuite(CipherAlgorithm.RC4, + KeyExchangeAlgorithm.PSK, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 16, 0x00, 0x8A, + "TLS_PSK_WITH_RC4_128_SHA"); + public static final CipherSuite TLS_PSK_WITH_3DES_EDE_CBC_SHA = + new CipherSuite(CipherAlgorithm.DESede, + KeyExchangeAlgorithm.PSK, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 24, 0x00, 0x8B, + "TLS_PSK_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_PSK_WITH_AES_128_CBC_SHA = + new CipherSuite(CipherAlgorithm.AES, + KeyExchangeAlgorithm.PSK, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 16, 0x00, 0x8C, + "TLS_PSK_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_PSK_WITH_AES_256_CBC_SHA = + new CipherSuite(CipherAlgorithm.AES, + KeyExchangeAlgorithm.PSK, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 32, 0x00, 0x8D, + "TLS_PSK_WITH_AES_256_CBC_SHA"); + + public static final CipherSuite TLS_DHE_PSK_WITH_RC4_128_SHA = + new CipherSuite(CipherAlgorithm.RC4, + KeyExchangeAlgorithm.DHE_PSK, true, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 16, 0x00, 0x8E, + "TLS_DHE_PSK_WITH_RC4_128_SHA"); + public static final CipherSuite TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA = + new CipherSuite(CipherAlgorithm.DESede, + KeyExchangeAlgorithm.DHE_PSK, true, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 24, 0x00, 0x8F, + "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_DHE_PSK_WITH_AES_128_CBC_SHA = + new CipherSuite(CipherAlgorithm.AES, + KeyExchangeAlgorithm.DHE_PSK, true, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 16, 0x00, 0x90, + "TLS_DHE_PSK_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_DHE_PSK_WITH_AES_256_CBC_SHA = + new CipherSuite(CipherAlgorithm.AES, + KeyExchangeAlgorithm.DHE_PSK, true, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 32, 0x00, 0x91, + "TLS_DHE_PSK_WITH_AES_256_CBC_SHA"); + + public static final CipherSuite TLS_RSA_PSK_WITH_RC4_128_SHA = + new CipherSuite(CipherAlgorithm.RC4, + KeyExchangeAlgorithm.RSA_PSK, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 16, 0x00, 0x92, + "TLS_RSA_PSK_WITH_RC4_128_SHA"); + public static final CipherSuite TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA = + new CipherSuite(CipherAlgorithm.DESede, + KeyExchangeAlgorithm.RSA_PSK, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 24, 0x00, 0x93, + "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_RSA_PSK_WITH_AES_128_CBC_SHA = + new CipherSuite(CipherAlgorithm.AES, + KeyExchangeAlgorithm.RSA_PSK, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 16, 0x00, 0x94, + "TLS_RSA_PSK_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_RSA_PSK_WITH_AES_256_CBC_SHA = + new CipherSuite(CipherAlgorithm.AES, + KeyExchangeAlgorithm.RSA_PSK, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 32, 0x00, 0x95, + "TLS_RSA_PSK_WITH_AES_256_CBC_SHA"); + + // Ciphersuites from the OpenPGP extension draft. + // These disappeared from a more recent draft. +/* public static final CipherSuite TLS_DHE_DSS_WITH_CAST_128_CBC_SHA = + new CipherSuite (CipherAlgorithm.CAST5, + KeyExchangeAlgorithm.DIFFIE_HELLMAN, true, + SignatureAlgorithm.DSA, + MacAlgorithm.SHA, 16, 0x00, 0x70, + "TLS_DHE_DSS_WITH_CAST_128_CBC_SHA"); + public static final CipherSuite TLS_DHE_DSS_WITH_CAST_128_CBC_RMD = + new CipherSuite (CipherAlgorithm.CAST5, + KeyExchangeAlgorithm.DIFFIE_HELLMAN, true, + SignatureAlgorithm.DSA, + MacAlgorithm.HMAC_RMD, 16, 0x00, 0x71, + "TLS_DHE_DSS_WITH_CAST_128_CBC_RMD"); + public static final CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD = + new CipherSuite (CipherAlgorithm.DESede, + KeyExchangeAlgorithm.DIFFIE_HELLMAN, true, + SignatureAlgorithm.DSA, + MacAlgorithm.HMAC_RMD, 24, 0x00, 0x72, + "TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD"); + public static final CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_RMD = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.DIFFIE_HELLMAN, true, + SignatureAlgorithm.DSA, + MacAlgorithm.HMAC_RMD, 16, 0x00, 0x73, + "TLS_DHE_DSS_WITH_AES_128_CBC_RMD"); + public static final CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_RMD = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.DIFFIE_HELLMAN, true, + SignatureAlgorithm.DSA, + MacAlgorithm.HMAC_RMD, 32, 0x00, 0x74, + "TLS_DHE_DSS_WITH_AES_256_CBC_RMD"); + public static final CipherSuite TLS_DHE_RSA_WITH_CAST_128_CBC_SHA = + new CipherSuite (CipherAlgorithm.CAST5, + KeyExchangeAlgorithm.DIFFIE_HELLMAN, true, + SignatureAlgorithm.RSA, + MacAlgorithm.SHA, 16, 0x00, 0x75, + "TLS_DHE_RSA_WITH_CAST_128_CBC_SHA"); + public static final CipherSuite TLS_DHE_RSA_WITH_CAST_128_CBC_RMD = + new CipherSuite (CipherAlgorithm.CAST5, + KeyExchangeAlgorithm.DIFFIE_HELLMAN, true, + SignatureAlgorithm.RSA, + MacAlgorithm.HMAC_RMD, 16, 0x00, 0x76, + "TLS_DHE_RSA_WITH_CAST_128_CBC_RMD"); + public static final CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD = + new CipherSuite (CipherAlgorithm.DESede, + KeyExchangeAlgorithm.DIFFIE_HELLMAN, true, + SignatureAlgorithm.RSA, + MacAlgorithm.HMAC_RMD, 24, 0x00, 0x77, + "TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD"); + public static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_RMD = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.DIFFIE_HELLMAN, true, + SignatureAlgorithm.RSA, + MacAlgorithm.HMAC_RMD, 16, 0x00, 0x78, + "TLS_DHE_RSA_WITH_AES_128_CBC_RMD"); + public static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_RMD = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.DIFFIE_HELLMAN, true, + SignatureAlgorithm.RSA, + MacAlgorithm.HMAC_RMD, 32, 0x00, 0x79, + "TLS_DHE_RSA_WITH_AES_256_CBC_RMD"); + public static final CipherSuite TLS_RSA_WITH_CAST_128_CBC_SHA = + new CipherSuite (CipherAlgorithm.CAST5, + KeyExchangeAlgorithm.RSA, + SignatureAlgorithm.RSA, + MacAlgorithm.SHA, 16, 0x00, 0x7A, + "TLS_RSA_WITH_CAST_128_CBC_SHA"); + public static final CipherSuite TLS_RSA_WITH_CAST_128_CBC_RMD = + new CipherSuite (CipherAlgorithm.CAST5, + KeyExchangeAlgorithm.RSA, + SignatureAlgorithm.RSA, + MacAlgorithm.HMAC_RMD, 16, 0x00, 0x7B, + "TLS_RSA_WITH_CAST_128_CBC_RMD"); + public static final CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_RMD = + new CipherSuite (CipherAlgorithm.DESede, + KeyExchangeAlgorithm.RSA, + SignatureAlgorithm.RSA, + MacAlgorithm.HMAC_RMD, 24, 0x00, 0x7C, + "TLS_RSA_WITH_3DES_EDE_CBC_RMD"); + public static final CipherSuite TLS_RSA_WITH_AES_128_CBC_RMD = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.RSA, + SignatureAlgorithm.RSA, + MacAlgorithm.HMAC_RMD, 16, 0x00, 0x7D, + "TLS_RSA_WITH_AES_128_CBC_RMD"); + public static final CipherSuite TLS_RSA_WITH_AES_256_CBC_RMD = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.RSA, + SignatureAlgorithm.RSA, + MacAlgorithm.HMAC_RMD, 32, 0x00, 0x7E, + "TLS_RSA_WITH_AES_256_CBC_RMD"); */ + + private final CipherAlgorithm cipherAlgorithm; + private final KeyExchangeAlgorithm keyExchangeAlgorithm; + private final SignatureAlgorithm signatureAlgorithm; + private final MacAlgorithm macAlgorithm; + private final boolean ephemeralDH; + private final boolean exportable; + private final boolean isStream; + private final int keyLength; + private final byte[] id; + private final String name; + private final boolean isResolved; + + // Constructors. + // ------------------------------------------------------------------------- + + private CipherSuite (final CipherAlgorithm cipherAlgorithm, + final KeyExchangeAlgorithm keyExchangeAlgorithm, + final SignatureAlgorithm signatureAlgorithm, + final MacAlgorithm macAlgorithm, + final int keyLength, + final int id1, + final int id2, + final String name) + { + this (cipherAlgorithm, keyExchangeAlgorithm, false, signatureAlgorithm, + macAlgorithm, keyLength, id1, id2, name); + } + + private CipherSuite (final CipherAlgorithm cipherAlgorithm, + final KeyExchangeAlgorithm keyExchangeAlgorithm, + final boolean ephemeralDH, + final SignatureAlgorithm signatureAlgorithm, + final MacAlgorithm macAlgorithm, + final int keyLength, + final int id1, + final int id2, + final String name) + { + this.cipherAlgorithm = cipherAlgorithm; + this.keyExchangeAlgorithm = keyExchangeAlgorithm; + this.ephemeralDH = ephemeralDH; + this.signatureAlgorithm = signatureAlgorithm; + this.macAlgorithm = macAlgorithm; + this.exportable = keyLength <= 5; + this.isStream = (cipherAlgorithm == CipherAlgorithm.NULL + || cipherAlgorithm == CipherAlgorithm.RC4); + this.keyLength = keyLength; + this.id = new byte[] { (byte) id1, (byte) id2 }; + this.name = name.intern(); + namesToSuites.put(name, this); + if (name.startsWith("TLS")) + { + tlsSuiteNames.add(name); + } + isResolved = true; + } + + private CipherSuite(byte[] id) + { + cipherAlgorithm = null; + keyExchangeAlgorithm = null; + signatureAlgorithm = null; + macAlgorithm = null; + ephemeralDH = false; + exportable = false; + isStream = false; + keyLength = 0; + this.id = id; + name = null; + isResolved = false; + } + + // Class methods. + // ------------------------------------------------------------------------- + + /** + * Returns the cipher suite for the given name, or null if there is no + * such suite. + * + * @return The named cipher suite. + */ + public static CipherSuite forName(String name) + { + if (name.startsWith("SSL_")) + name = "TLS_" + name.substring(4); + return namesToSuites.get(name); + } + + public static CipherSuite forValue(final short raw_value) + { + byte[] b = new byte[] { (byte) (raw_value >>> 8), (byte) raw_value }; + return new CipherSuite(b).resolve(); + } + + public static List availableSuiteNames() + { + return tlsSuiteNames; + } + + // Intance methods. + // ------------------------------------------------------------------------- + + public CipherAlgorithm cipherAlgorithm () + { + return cipherAlgorithm; + } + + public Cipher cipher () throws NoSuchAlgorithmException, NoSuchPaddingException + { + if (cipherAlgorithm == null) + throw new NoSuchAlgorithmException (toString () + ": unresolved cipher suite"); + if (cipherAlgorithm == CipherAlgorithm.NULL) + return new NullCipher (); + + String alg = null; + if (cipherAlgorithm == CipherAlgorithm.RC4) + alg = "RC4"; + else + alg = cipherAlgorithm + "/CBC/NoPadding"; + GetSecurityPropertyAction gspa = + new GetSecurityPropertyAction ("jessie.jce.provider"); + final String provider = (String) AccessController.doPrivileged (gspa); + if (provider != null) + { + try + { + return Cipher.getInstance (alg, provider); + } + catch (NoSuchProviderException nspe) + { + } + } + return Cipher.getInstance (alg); + } + + public MacAlgorithm macAlgorithm () + { + return macAlgorithm; + } + + public Mac mac(ProtocolVersion version) throws NoSuchAlgorithmException + { + if (macAlgorithm == null) + throw new NoSuchAlgorithmException(toString() + ": unresolved cipher suite"); + if (macAlgorithm == MacAlgorithm.NULL) + return null; + + String macAlg = null; + if (version == ProtocolVersion.SSL_3) + { + macAlg = "SSLv3HMac-" + macAlgorithm; + } + else + { + if (macAlgorithm == MacAlgorithm.MD5) + macAlg = "HMac-MD5"; + if (macAlgorithm == MacAlgorithm.SHA) + macAlg = "HMac-SHA1"; + } + + GetSecurityPropertyAction gspa = + new GetSecurityPropertyAction ("jessie.jce.provider"); + final String provider = AccessController.doPrivileged (gspa); + if (provider != null) + { + try + { + return Mac.getInstance(macAlg, provider); + } + catch (NoSuchProviderException nspe) + { + // Ignore; try any installed provider. + } + } + return Mac.getInstance(macAlg); + } + + public SignatureAlgorithm signatureAlgorithm () + { + return signatureAlgorithm; + } + + public KeyExchangeAlgorithm keyExchangeAlgorithm () + { + return keyExchangeAlgorithm; + } + + public boolean isEphemeralDH () + { + return ephemeralDH; + } + + public int length () + { + return 2; + } + + public void write(OutputStream out) throws IOException + { + out.write(id); + } + + public void put (final ByteBuffer buf) + { + buf.put (id); + } + + public CipherSuite resolve() + { + if (id[0] == 0x00) switch (id[1] & 0xFF) + { + case 0x00: return TLS_NULL_WITH_NULL_NULL; + case 0x01: return TLS_RSA_WITH_NULL_MD5; + case 0x02: return TLS_RSA_WITH_NULL_SHA; + case 0x03: return TLS_RSA_EXPORT_WITH_RC4_40_MD5; + case 0x04: return TLS_RSA_WITH_RC4_128_MD5; + case 0x05: return TLS_RSA_WITH_RC4_128_SHA; + case 0x08: return TLS_RSA_EXPORT_WITH_DES40_CBC_SHA; + case 0x09: return TLS_RSA_WITH_DES_CBC_SHA; + case 0x0A: return TLS_RSA_WITH_3DES_EDE_CBC_SHA; + case 0x0B: return TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA; + case 0x0C: return TLS_DH_DSS_WITH_DES_CBC_SHA; + case 0x0D: return TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA; + case 0x0E: return TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA; + case 0x0F: return TLS_DH_RSA_WITH_DES_CBC_SHA; + case 0x10: return TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA; + case 0x11: return TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA; + case 0x12: return TLS_DHE_DSS_WITH_DES_CBC_SHA; + case 0x13: return TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA; + case 0x14: return TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA; + case 0x15: return TLS_DHE_RSA_WITH_DES_CBC_SHA; + case 0x16: return TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA; + case 0x2F: return TLS_RSA_WITH_AES_128_CBC_SHA; + case 0x30: return TLS_DH_DSS_WITH_AES_128_CBC_SHA; + case 0x31: return TLS_DH_RSA_WITH_AES_128_CBC_SHA; + case 0x32: return TLS_DHE_DSS_WITH_AES_128_CBC_SHA; + case 0x33: return TLS_DHE_RSA_WITH_AES_128_CBC_SHA; + case 0x35: return TLS_RSA_WITH_AES_256_CBC_SHA; + case 0x36: return TLS_DH_DSS_WITH_AES_256_CBC_SHA; + case 0x37: return TLS_DH_RSA_WITH_AES_256_CBC_SHA; + case 0x38: return TLS_DHE_DSS_WITH_AES_256_CBC_SHA; + case 0x39: return TLS_DHE_RSA_WITH_AES_256_CBC_SHA; + /*case 0x50: return TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA; + case 0x51: return TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA; + case 0x52: return TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA; + case 0x53: return TLS_SRP_SHA_WITH_AES_128_CBC_SHA; + case 0x54: return TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA; + case 0x55: return TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA; + case 0x56: return TLS_SRP_SHA_WITH_AES_256_CBC_SHA; + case 0x57: return TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA; + case 0x58: return TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA; + case 0x70: return TLS_DHE_DSS_WITH_CAST_128_CBC_SHA; + case 0x71: return TLS_DHE_DSS_WITH_CAST_128_CBC_RMD; + case 0x72: return TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD; + case 0x73: return TLS_DHE_DSS_WITH_AES_128_CBC_RMD; + case 0x74: return TLS_DHE_DSS_WITH_AES_256_CBC_RMD; + case 0x75: return TLS_DHE_RSA_WITH_CAST_128_CBC_SHA; + case 0x76: return TLS_DHE_RSA_WITH_CAST_128_CBC_RMD; + case 0x77: return TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD; + case 0x78: return TLS_DHE_RSA_WITH_AES_128_CBC_RMD; + case 0x79: return TLS_DHE_RSA_WITH_AES_256_CBC_RMD; + case 0x7A: return TLS_RSA_WITH_CAST_128_CBC_SHA; + case 0x7B: return TLS_RSA_WITH_CAST_128_CBC_RMD; + case 0x7C: return TLS_RSA_WITH_3DES_EDE_CBC_RMD; + case 0x7D: return TLS_RSA_WITH_AES_128_CBC_RMD; + case 0x7E: return TLS_RSA_WITH_AES_256_CBC_RMD;*/ + case 0x8A: return TLS_PSK_WITH_RC4_128_SHA; + case 0x8B: return TLS_PSK_WITH_3DES_EDE_CBC_SHA; + case 0x8C: return TLS_PSK_WITH_AES_128_CBC_SHA; + case 0x8D: return TLS_PSK_WITH_AES_256_CBC_SHA; + case 0x8E: return TLS_DHE_PSK_WITH_RC4_128_SHA; + case 0x8F: return TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA; + case 0x90: return TLS_DHE_PSK_WITH_AES_128_CBC_SHA; + case 0x91: return TLS_DHE_PSK_WITH_AES_256_CBC_SHA; + case 0x92: return TLS_RSA_PSK_WITH_RC4_128_SHA; + case 0x93: return TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA; + case 0x94: return TLS_RSA_PSK_WITH_AES_128_CBC_SHA; + case 0x95: return TLS_RSA_PSK_WITH_AES_256_CBC_SHA; + } + return this; + } + + public boolean isResolved() + { + return isResolved; + } + + public int keyLength() + { + return keyLength; + } + + public boolean isExportable() + { + return exportable; + } + + public boolean isStreamCipher() + { + return isStream; + } + +// String getAuthType() +// { +// if (keyExchangeAlgorithm == KeyExchangeAlgorithm.RSA) +// { +// if (isExportable()) +// { +// return "RSA_EXPORT"; +// } +// return "RSA"; +// } +// return kexName + "_" + sigName; +// } + + public byte[] id() + { + return id; + } + + public boolean equals(Object o) + { + if (!(o instanceof CipherSuite)) + { + return false; + } + if (o == this) + return true; + byte[] id = ((CipherSuite) o).id(); + return (id[0] == this.id[0] && + id[1] == this.id[1]); + } + + public int hashCode() + { + return 0xFFFF0000 | (id[0] & 0xFF) << 8 | (id[1] & 0xFF); + } + + public String toString (String prefix) + { + return toString (); + } + + public String toString() + { + if (name == null) + { + return "{ " + (id[0] & 0xFF) + ", " + (id[1] & 0xFF) + " }"; + } + return name; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CipherSuiteList.java b/libjava/classpath/gnu/javax/net/ssl/provider/CipherSuiteList.java new file mode 100644 index 000000000..a12304698 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/ClientCertificateTypeList.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientCertificateTypeList.java new file mode 100644 index 000000000..4dd64f09f --- /dev/null +++ b/libjava/classpath/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); + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java new file mode 100644 index 000000000..e2362e029 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/ClientDiffieHellmanPublic.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientDiffieHellmanPublic.java new file mode 100644 index 000000000..393313a2f --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/ClientHandshake.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHandshake.java new file mode 100644 index 000000000..c938e284a --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHandshake.java @@ -0,0 +1,1153 @@ +/* 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.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.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.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]; + if (cert instanceof X509Certificate) + { + boolean[] keyUsage = ((X509Certificate) cert).getKeyUsage(); + if (keyUsage != null && !keyUsage[2]) + throw new InvalidKeyException("certificate's keyUsage does not permit keyEncipherment"); + } + rsa.init(Cipher.ENCRYPT_MODE, cert.getPublicKey()); + encryptedPreMasterSecret = rsa.doFinal(preMasterSecret); + + // Generate our session keys, because we can. + if (full) + { + generateMasterSecret(clientRandom, serverRandom, engine.session()); + byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session()); + setupSecurityParameters(keys, true, engine, compression); + } + } + + byte[] encryptedSecret() + { + return encryptedPreMasterSecret; + } + } + + class GenCertVerify extends DelegatedTask + { + private final MessageDigest md5, sha; + private byte[] signed; + + GenCertVerify(MessageDigest md5, MessageDigest sha) + { + try + { + this.md5 = (MessageDigest) md5.clone(); + this.sha = (MessageDigest) sha.clone(); + } + catch (CloneNotSupportedException cnse) + { + // Our message digests *should* be cloneable. + throw new Error(cnse); + } + } + + public void implRun() + throws InvalidKeyException, NoSuchAlgorithmException, SignatureException + { + byte[] toSign; + if (engine.session().version == ProtocolVersion.SSL_3) + { + toSign = genV3CertificateVerify(md5, sha, engine.session()); + } + else + { + if (engine.session().suite.signatureAlgorithm() == SignatureAlgorithm.RSA) + toSign = Util.concat(md5.digest(), sha.digest()); + else + toSign = sha.digest(); + } + + java.security.Signature sig = + java.security.Signature.getInstance(engine.session().suite.signatureAlgorithm().name()); + sig.initSign(privateKey); + sig.update(toSign); + signed = sig.sign(); + } + + byte[] signed() + { + return signed; + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientHello.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHello.java new file mode 100644 index 000000000..a58dc5d7a --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHello.java @@ -0,0 +1,240 @@ +/* ClientHello.java -- SSL ClientHello message. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.PrintWriter; +import java.io.StringWriter; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * A ClientHello handshake message. + * + *
+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. + // ------------------------------------------------------------------------- + + // To help track offsets into the message: + // The location of the 'random' field. + protected static final int RANDOM_OFFSET = 2; + // The location of the sesion_id length. + protected static final int SESSID_OFFSET = 32 + RANDOM_OFFSET; + // The location of the session_id bytes (if any). + protected static final int SESSID_OFFSET2 = SESSID_OFFSET + 1; + + protected ByteBuffer buffer; + protected boolean disableExtensions; + + // Constructor. + // ------------------------------------------------------------------------- + + public ClientHello (final ByteBuffer buffer) + { + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); + disableExtensions = false; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public int length() + { + int len = SESSID_OFFSET2 + buffer.get(SESSID_OFFSET); + len += (buffer.getShort(len) & 0xFFFF) + 2; + len += (buffer.get(len) & 0xFF) + 1; + if (!disableExtensions && len + 1 < buffer.capacity()) + len += (buffer.getShort(len) & 0xFFFF) + 2; + return len; + } + + /** + * Gets the protocol version field. + * + * @return The protocol version field. + */ + public ProtocolVersion version() + { + return ProtocolVersion.getInstance (buffer.getShort (0)); + } + + /** + * Gets the SSL nonce. + * + * @return The nonce. + */ + public Random random() + { + ByteBuffer randomBuf = + ((ByteBuffer) buffer.duplicate ().position (RANDOM_OFFSET) + .limit (SESSID_OFFSET)).slice (); + return new Random (randomBuf); + } + + public byte[] sessionId() + { + int idlen = buffer.get (SESSID_OFFSET) & 0xFF; + byte[] sessionId = new byte[idlen]; + buffer.position (SESSID_OFFSET2); + buffer.get (sessionId); + return sessionId; + } + + public CipherSuiteList cipherSuites() + { + int offset = getCipherSuitesOffset (); + + // We give the CipherSuiteList all the remaining bytes to play with, + // since this might be an in-construction packet that will fill in + // the length field itself. + ByteBuffer listBuf = ((ByteBuffer) buffer.duplicate ().position (offset) + .limit (buffer.capacity ())).slice (); + return new CipherSuiteList (listBuf, version ()); + } + + public CompressionMethodList compressionMethods() + { + int offset = getCompressionMethodsOffset (); + ByteBuffer listBuf = ((ByteBuffer) buffer.duplicate ().position (offset) + .limit (buffer.capacity ())).slice (); + return new CompressionMethodList (listBuf); + } + + public boolean hasExtensions() + { + int offset = getExtensionsOffset(); + return (offset + 1 < buffer.limit()); + } + + public ExtensionList extensions() + { + int offset = getExtensionsOffset (); + if (offset + 1 >= buffer.limit()) + return null; + int len = buffer.getShort(offset) & 0xFFFF; + if (len == 0) + len = buffer.limit() - offset - 2; + ByteBuffer ebuf = ((ByteBuffer) buffer.duplicate().position(offset) + .limit(offset + len + 2)).slice (); + return new ExtensionList(ebuf); + } + + public int extensionsLength() + { + if (hasExtensions()) + return 0; + return buffer.getShort(getExtensionsOffset()) & 0xFFFF; + } + + protected int getCipherSuitesOffset () + { + return (SESSID_OFFSET2 + (buffer.get (SESSID_OFFSET) & 0xFF)); + } + + protected int getCompressionMethodsOffset () + { + int csOffset = getCipherSuitesOffset (); + int csLen = buffer.getShort (csOffset) & 0xFFFF; + return csOffset + csLen + 2; + } + + protected int getExtensionsOffset () + { + int cmOffset = getCompressionMethodsOffset (); + return (buffer.get (cmOffset) & 0xFF) + cmOffset + 1; + } + + public String toString () + { + return toString (null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter (); + PrintWriter out = new PrintWriter (str); + String subprefix = " "; + if (prefix != null) + subprefix += prefix; + if (prefix != null) + out.print (prefix); + out.println ("struct {"); + if (prefix != null) + out.print (prefix); + out.print (" version: "); + out.print (version ()); + out.println (";"); + out.print (subprefix); + out.println ("random:"); + out.print (random ().toString (subprefix)); + if (prefix != null) + out.print (prefix); + out.print (" sessionId: "); + out.print (Util.toHexString (sessionId (), ':')); + out.println (";"); + out.print (subprefix); + out.println ("cipher_suites:"); + out.println (cipherSuites ().toString (subprefix)); + out.print (subprefix); + out.println ("compression_methods:"); + out.println (compressionMethods ().toString (subprefix)); + out.print (subprefix); + out.print ("extensions: "); + ExtensionList el = extensions(); + out.println (el != null ? el.toString(subprefix+" ") : "(nil)"); + if (prefix != null) + out.print (prefix); + out.print ("} ClientHello;"); + return str.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloBuilder.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloBuilder.java new file mode 100644 index 000000000..90405c45b --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloV2.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloV2.java new file mode 100644 index 000000000..6009d52a3 --- /dev/null +++ b/libjava/classpath/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 (); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchange.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchange.java new file mode 100644 index 000000000..2006e7385 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchange.java @@ -0,0 +1,132 @@ +/* ClientKeyExchange.java -- SSL ClientKeyExchange message. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.PrintWriter; +import java.io.StringWriter; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * The client key exchange message. + * + *
+struct {
+  select (KeyExchangeAlgorithm) {
+    case rsa: EncryptedPreMasterSecret;
+    case diffie_hellman: ClientDiffieHellmanPublic;
+  } exchange_keys;
+} ClientKeyExchange;
+ */ +public class ClientKeyExchange implements Handshake.Body +{ + + // Fields. + // ------------------------------------------------------------------------- + + protected ByteBuffer buffer; + protected final CipherSuite suite; + protected final ProtocolVersion version; + + // Constructors. + // ------------------------------------------------------------------------- + + public ClientKeyExchange (final ByteBuffer buffer, final CipherSuite suite, + final ProtocolVersion version) + { + suite.getClass(); + version.getClass (); + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); + this.suite = suite; + this.version = version; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public ExchangeKeys exchangeKeys () + { + KeyExchangeAlgorithm alg = suite.keyExchangeAlgorithm(); + if (alg == KeyExchangeAlgorithm.RSA) + return new EncryptedPreMasterSecret(buffer, version); + else if (alg == KeyExchangeAlgorithm.DH_anon + || alg == KeyExchangeAlgorithm.DHE_DSS + || alg == KeyExchangeAlgorithm.DHE_RSA) + return new ClientDiffieHellmanPublic(buffer.duplicate()); + else if (alg == KeyExchangeAlgorithm.DHE_PSK) + return new ClientDHE_PSKParameters(buffer.duplicate()); + else if (alg == KeyExchangeAlgorithm.PSK) + return new ClientPSKParameters(buffer.duplicate()); + else if (alg == KeyExchangeAlgorithm.RSA_PSK) + return new ClientRSA_PSKParameters(buffer.duplicate()); + else if (alg == KeyExchangeAlgorithm.NONE) + return new EmptyExchangeKeys(); + throw new IllegalArgumentException("unsupported key exchange: " + alg); + } + + public int length() + { + if (suite.keyExchangeAlgorithm() == KeyExchangeAlgorithm.NONE) + return 0; + return exchangeKeys().length(); + } + + public String toString () + { + return toString (null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) + out.print (prefix); + out.println("struct {"); + String subprefix = " "; + if (prefix != null) + subprefix = prefix + subprefix; + out.println (exchangeKeys ().toString (subprefix)); + if (prefix != null) + out.print (prefix); + out.println("} ClientKeyExchange;"); + return str.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchangeBuilder.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchangeBuilder.java new file mode 100644 index 000000000..a43873510 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/ClientPSKParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientPSKParameters.java new file mode 100644 index 000000000..22c6333e9 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientPSKParameters.java @@ -0,0 +1,121 @@ +/* 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 java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.ByteBuffer; +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/libjava/classpath/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java new file mode 100644 index 000000000..842e911d0 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java @@ -0,0 +1,122 @@ +/* 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 java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.ByteBuffer; +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/libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethod.java b/libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethod.java new file mode 100644 index 000000000..3005dd9fc --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethod.java @@ -0,0 +1,69 @@ +/* CompressionMethod.java -- The CompressionMethod enum. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +public enum CompressionMethod +{ + NULL (0), ZLIB(1); + + private final int value; + + private CompressionMethod(int value) + { + this.value = value; + } + + public static CompressionMethod getInstance (final int value) + { + switch (value & 0xFF) + { + case 0: return NULL; + case 1: return ZLIB; + + // Note: we can't throw an exception here, because we get these values + // over the wire, and need to just ignore ones we don't recognize. + default: return null; + } + } + + public int getValue() + { + return value; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethodList.java b/libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethodList.java new file mode 100644 index 000000000..b57e0c6a6 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/Constructed.java b/libjava/classpath/gnu/javax/net/ssl/provider/Constructed.java new file mode 100644 index 000000000..23ff68812 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Constructed.java @@ -0,0 +1,86 @@ +/* Constructed.java -- Constructed type. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +/** + * The base interface to SSL constructed types. + * + *

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. + */ +public interface Constructed +{ + /** + * Returns the total length, in bytes, of this structure. + * + * @return The length of this structure. + */ + int length(); + + /** + * Returns a printable representation of this structure, with the + * given prefix prepended to each line. + * + * @param prefix The prefix to prepend to each line of the + * output. This value may be null. + * @return A printable representation of this structure. + */ + String toString(String prefix); +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ContentType.java b/libjava/classpath/gnu/javax/net/ssl/provider/ContentType.java new file mode 100644 index 000000000..eaebebf4b --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ContentType.java @@ -0,0 +1,89 @@ +/* ContentType.java -- SSL record layer content type. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +/** + * 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;
+ * + *

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) + */ +public enum ContentType +{ + + CLIENT_HELLO_V2 ( 1), + CHANGE_CIPHER_SPEC (20), + ALERT (21), + HANDSHAKE (22), + APPLICATION_DATA (23); + + private int value; + + // Constructors. + // ------------------------------------------------------------------------ + + private ContentType(int value) + { + this.value = value; + } + + static final ContentType forInteger (final int value) + { + switch (value & 0xFF) + { + case 1: return CLIENT_HELLO_V2; + case 20: return CHANGE_CIPHER_SPEC; + case 21: return ALERT; + case 22: return HANDSHAKE; + case 23: return APPLICATION_DATA; + default: return null; + } + } + + public int getValue() + { + return value; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Debug.java b/libjava/classpath/gnu/javax/net/ssl/provider/Debug.java new file mode 100644 index 000000000..308ef67a0 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/DelegatedTask.java b/libjava/classpath/gnu/javax/net/ssl/provider/DelegatedTask.java new file mode 100644 index 000000000..34fd39d19 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/DiffieHellman.java b/libjava/classpath/gnu/javax/net/ssl/provider/DiffieHellman.java new file mode 100644 index 000000000..5a5275712 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/DiffieHellman.java @@ -0,0 +1,289 @@ +/* DiffieHellman.java -- Diffie-Hellman key exchange. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.math.BigInteger; +import java.security.AccessController; + +import gnu.java.security.action.GetSecurityPropertyAction; +import gnu.javax.crypto.key.dh.GnuDHPrivateKey; + +/** + *

Simple implementation of two-party Diffie-Hellman key agreement.

+ * + *

The primes used in this class are from the following documents:

+ * + *
    + *
  • D. Harkins and D. Carrel, "The Internet Key Exchange (IKE)", RFC 2409.
  • + *
  • T. Kivinen and M. Kojo, "More Modular + * Exponential (MODP) Diffie-Hellman groups for Internet Key Exchange + * (IKE)", RFC + * 3526.
  • + * + * + *

    The generator for all these primes is 2.

    + */ +final class DiffieHellman +{ + + // Class method. + // ------------------------------------------------------------------------- + + /** + * Get the system's Diffie-Hellman parameters, in which g is 2 + * and p is determined by the property + * "jessie.keypool.dh.group". The default value for p + * is 18, corresponding to {@link #GROUP_18}. + */ + static GnuDHPrivateKey getParams() + { + BigInteger p = DiffieHellman.GROUP_5; + String group = AccessController.doPrivileged + (new GetSecurityPropertyAction("jessie.key.dh.group")); + if (group != null) + { + group = group.trim(); + if (group.equals("1")) + p = DiffieHellman.GROUP_1; + else if (group.equals("2")) + p = DiffieHellman.GROUP_2; + else if (group.equals("5")) + p = DiffieHellman.GROUP_5; + else if (group.equals("14")) + p = DiffieHellman.GROUP_14; + else if (group.equals("15")) + p = DiffieHellman.GROUP_15; + else if (group.equals("16")) + p = DiffieHellman.GROUP_16; + else if (group.equals("17")) + p = DiffieHellman.GROUP_17; + else if (group.equals("18")) + p = DiffieHellman.GROUP_18; + } + return new GnuDHPrivateKey(null, p, DH_G, null); + } + + // Constants. + // ------------------------------------------------------------------------- + + /** + * The generator for all Diffie Hellman groups below. + */ + static final BigInteger DH_G = BigInteger.valueOf(2L); + + /** + * p = 2^768 - 2 ^704 - 1 + 2^64 * { [2^638 pi] + 149686 } + */ + static final BigInteger GROUP_1 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF", 16); + + /** + * p = 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 } + */ + static final BigInteger GROUP_2 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" + + "FFFFFFFFFFFFFFFF", 16); + + /** + * This prime p = 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 }. + */ + static final BigInteger GROUP_5 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", 16); + + /** + * p = 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 }. + */ + static final BigInteger GROUP_14 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + + "15728E5A8AACAA68FFFFFFFFFFFFFFFF", 16); + + /** + * p = 2^3072 - 2^3008 - 1 + 2^64 * { [2^2942 pi] + 1690314 }. + */ + static final BigInteger GROUP_15 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" + + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" + + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" + + "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF", 16); + + /** + * p = 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 }. + */ + static final BigInteger GROUP_16 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" + + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" + + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" + + "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" + + "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" + + "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" + + "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" + + "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" + + "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" + + "FFFFFFFFFFFFFFFF", 16); + + static final BigInteger GROUP_17 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" + + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" + + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" + + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" + + "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8" + + "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C" + + "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718" + + "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D" + + "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D" + + "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226" + + "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC" + + "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26" + + "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB" + + "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2" + + "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127" + + "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" + + "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406" + + "AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918" + + "DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151" + + "2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03" + + "F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F" + + "BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" + + "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B" + + "B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632" + + "387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E" + + "6DCC4024FFFFFFFFFFFFFFFF", 16); + + /** + * p = 2^8192 - 2^8128 - 1 + 2^64 * { [2^8062 pi] + 4743158 }. + * + *

    This value, while quite large, is estimated to provide the equivalent + * cryptographic strength of a symmetric key between 190 and 320 bits. + */ + static final BigInteger GROUP_18 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" + + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" + + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" + + "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" + + "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" + + "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" + + "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" + + "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" + + "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" + + "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" + + "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" + + "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" + + "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" + + "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" + + "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" + + "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" + + "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" + + "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" + + "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" + + "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4" + + "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300" + + "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568" + + "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9" + + "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B" + + "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A" + + "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36" + + "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1" + + "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92" + + "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47" + + "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" + + "60C980DD98EDD3DFFFFFFFFFFFFFFFFF", 16); + +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/EmptyExchangeKeys.java b/libjava/classpath/gnu/javax/net/ssl/provider/EmptyExchangeKeys.java new file mode 100644 index 000000000..55b59998d --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java b/libjava/classpath/gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java new file mode 100644 index 000000000..a40223dd0 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java @@ -0,0 +1,148 @@ +/* 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 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(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ExchangeKeys.java b/libjava/classpath/gnu/javax/net/ssl/provider/ExchangeKeys.java new file mode 100644 index 000000000..a6664b856 --- /dev/null +++ b/libjava/classpath/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); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Extension.java b/libjava/classpath/gnu/javax/net/ssl/provider/Extension.java new file mode 100644 index 000000000..5cbcd5790 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Extension.java @@ -0,0 +1,246 @@ +/* Extension.java -- A TLS hello extension. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.PrintWriter; +import java.io.StringWriter; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * An SSL hello extension. + * + *
    + * 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 ByteBuffer buffer; + + // Constructor. + // ------------------------------------------------------------------------- + + public Extension(final ByteBuffer buffer) + { + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); + } + + public Extension(final Type type, final Value value) + { + ByteBuffer valueBuffer = value.buffer(); + int length = 2 + 2 + valueBuffer.remaining(); + buffer = ByteBuffer.allocate(length); + buffer.putShort((short) type.getValue()); + buffer.putShort((short) valueBuffer.remaining()); + buffer.put(valueBuffer); + buffer.rewind(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public int length () + { + return (buffer.getShort (2) & 0xFFFF) + 4; + } + + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().limit(length()); + } + + public Type type() + { + return Type.forValue (buffer.getShort (0) & 0xFFFF); + } + + public byte[] valueBytes() + { + int len = buffer.getShort (2) & 0xFFFF; + byte[] value = new byte[len]; + ((ByteBuffer) buffer.duplicate ().position (4)).get (value); + return value; + } + + public ByteBuffer valueBuffer() + { + int len = buffer.getShort(2) & 0xFFFF; + return ((ByteBuffer) buffer.duplicate().position(4).limit(len+4)).slice(); + } + + public Value value() + { + switch (type ()) + { + case SERVER_NAME: + return new ServerNameList(valueBuffer()); + + case MAX_FRAGMENT_LENGTH: + switch (valueBuffer().get() & 0xFF) + { + case 1: return MaxFragmentLength.LEN_2_9; + case 2: return MaxFragmentLength.LEN_2_10; + case 3: return MaxFragmentLength.LEN_2_11; + case 4: return MaxFragmentLength.LEN_2_12; + default: + throw new IllegalArgumentException("invalid max_fragment_len"); + } + + case TRUNCATED_HMAC: + return new TruncatedHMAC(); + + case CLIENT_CERTIFICATE_URL: + return new CertificateURL(valueBuffer()); + + case TRUSTED_CA_KEYS: + return new TrustedAuthorities(valueBuffer()); + + case STATUS_REQUEST: + return new CertificateStatusRequest(valueBuffer()); + + case SRP: + case CERT_TYPE: + } + return new UnresolvedExtensionValue(valueBuffer()); + } + + public void setLength (final int newLength) + { + if (newLength < 0 || newLength > 65535) + throw new IllegalArgumentException ("length is out of bounds"); + buffer.putShort (2, (short) newLength); + } + + public void setType (final Type type) + { + buffer.putShort(0, (short) type.getValue()); + } + + public void setValue (byte[] value) + { + setValue (value, 0, value.length); + } + + public void setValue (final byte[] value, final int offset, final int length) + { + if (length != length ()) + throw new IllegalArgumentException ("length is different than claimed length"); + ((ByteBuffer) buffer.duplicate().position(4)).put(value, offset, length); + } + + public String toString() + { + return toString(null); + } + + public String toString(String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) out.print (prefix); + out.println("struct {"); + if (prefix != null) out.print (prefix); + out.println(" type = " + type () + ";"); + if (prefix != null) out.print (prefix); + String subprefix = " "; + if (prefix != null) subprefix = prefix + subprefix; + out.println(" value ="); + out.println(value().toString(subprefix)); + if (prefix != null) out.print (prefix); + out.print("} Extension;"); + return str.toString(); + } + + // Inner classes. + // ------------------------------------------------------------------------- + + public static enum Type + { + SERVER_NAME (0), + MAX_FRAGMENT_LENGTH (1), + CLIENT_CERTIFICATE_URL (2), + TRUSTED_CA_KEYS (3), + TRUNCATED_HMAC (4), + STATUS_REQUEST (5), + SRP (6), + CERT_TYPE (7); + + private final int value; + + private Type(int value) + { + this.value = value; + } + + public static Type forValue (final int value) + { + switch (value & 0xFFFF) + { + case 0: return SERVER_NAME; + case 1: return MAX_FRAGMENT_LENGTH; + case 2: return CLIENT_CERTIFICATE_URL; + case 3: return TRUSTED_CA_KEYS; + case 4: return TRUNCATED_HMAC; + case 5: return STATUS_REQUEST; + case 6: return SRP; + case 7: return CERT_TYPE; + default: return null; + } + } + + public int getValue() + { + return value; + } + } + + public static abstract class Value implements Builder, Constructed + { + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ExtensionList.java b/libjava/classpath/gnu/javax/net/ssl/provider/ExtensionList.java new file mode 100644 index 000000000..fb7b12d9e --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/Finished.java b/libjava/classpath/gnu/javax/net/ssl/provider/Finished.java new file mode 100644 index 000000000..9a2a4707a --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Finished.java @@ -0,0 +1,173 @@ +/* Finished.java -- SSL Finished message. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.PrintWriter; +import java.io.StringWriter; + +import java.nio.ByteBuffer; + +final class Finished implements Handshake.Body +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final ByteBuffer buffer; + private final ProtocolVersion version; + + // Constructor. + // ------------------------------------------------------------------------- + + Finished (final ByteBuffer buffer, final ProtocolVersion version) + { + buffer.getClass (); + version.getClass (); + this.buffer = buffer; + this.version = version; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public int length () + { + if (version.compareTo(ProtocolVersion.TLS_1) >= 0) + return 12; + if (version == ProtocolVersion.SSL_3) + return 36; + throw new IllegalArgumentException ("length for this version unknown"); + } + + byte[] verifyData() + { + if (version.compareTo(ProtocolVersion.TLS_1) >= 0) + { + byte[] verify = new byte[12]; + buffer.position (0); + buffer.get (verify); + return verify; + } + throw new IllegalArgumentException ("not TLSv1.0 or later"); + } + + byte[] md5Hash() + { + if (version == ProtocolVersion.SSL_3) + { + byte[] md5 = new byte[16]; + buffer.position (0); + buffer.get (md5); + return md5; + } + throw new IllegalArgumentException ("not SSLv3"); + } + + byte[] shaHash() + { + if (version == ProtocolVersion.SSL_3) + { + byte[] sha = new byte[20]; + buffer.position (16); + buffer.get (sha); + return sha; + } + throw new IllegalArgumentException ("not SSLv3"); + } + + void setVerifyData (final byte[] verifyData, final int offset) + { + if (version == ProtocolVersion.SSL_3) + throw new IllegalArgumentException ("not TLSv1"); + buffer.position (0); + buffer.put (verifyData, offset, 12); + } + + void setMD5Hash (final byte[] md5, final int offset) + { + if (version != ProtocolVersion.SSL_3) + throw new IllegalArgumentException ("not SSLv3"); + buffer.position (0); + buffer.put (md5, offset, 16); + } + + void setShaHash (final byte[] sha, final int offset) + { + if (version != ProtocolVersion.SSL_3) + throw new IllegalArgumentException ("not SSLv3"); + buffer.position (16); + buffer.put (sha, offset, 20); + } + + public String toString () + { + return toString (null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter (); + PrintWriter out = new PrintWriter (str); + if (prefix != null) + out.print (prefix); + out.println ("struct {"); + if (prefix != null) + out.print (prefix); + if (version.compareTo(ProtocolVersion.TLS_1) >= 0) + { + out.print (" verifyData = "); + out.print (Util.toHexString (verifyData (), ':')); + } + else if (version == ProtocolVersion.SSL_3) + { + out.print (" md5 = "); + out.print (Util.toHexString (md5Hash (), ':')); + out.println (';'); + if (prefix != null) + out.print (prefix); + out.print (" sha = "); + out.print (Util.toHexString (shaHash (), ':')); + } + out.println (';'); + if (prefix != null) + out.print (prefix); + out.print ("} Finished;"); + return str.toString (); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Handshake.java b/libjava/classpath/gnu/javax/net/ssl/provider/Handshake.java new file mode 100644 index 000000000..31f142d3e --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Handshake.java @@ -0,0 +1,299 @@ +/* Handshake.java -- SSL Handshake message. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.PrintWriter; +import java.io.StringWriter; + +import java.nio.ByteBuffer; + +/** + * 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 final ByteBuffer buffer; + private final CipherSuite suite; + private final ProtocolVersion version; + + // Constructors. + // ------------------------------------------------------------------------- + + public Handshake (final ByteBuffer buffer) + { + this (buffer, null, ProtocolVersion.TLS_1_1); + } + + public Handshake (final ByteBuffer buffer, final CipherSuite suite, + final ProtocolVersion version) + { + this.buffer = buffer; + this.suite = suite; + this.version = version; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + /** + * Returns the handshake type. + * + * @return The handshake type. + */ + public Type type() + { + return Type.forInteger (buffer.get (0) & 0xFF); + } + + /** + * Returns the message length. + * + * @return The message length. + */ + public int length () + { + // Length is a uint24. + return buffer.getInt (0) & 0xFFFFFF; + } + + /** + * Returns the handshake message body. Depending on the handshake + * type, some implementation of the Body interface is returned. + * + * @return The handshake body. + */ + public Body body() + { + Type type = type (); + ByteBuffer bodyBuffer = bodyBuffer (); + switch (type) + { + case HELLO_REQUEST: + return new HelloRequest (); + + case CLIENT_HELLO: + return new ClientHello (bodyBuffer); + + case SERVER_HELLO: + return new ServerHello (bodyBuffer); + + case CERTIFICATE: + return new Certificate (bodyBuffer, CertificateType.X509); + + case SERVER_KEY_EXCHANGE: + return new ServerKeyExchange (bodyBuffer, suite); + + case CERTIFICATE_REQUEST: + return new CertificateRequest (bodyBuffer); + + case SERVER_HELLO_DONE: + return new ServerHelloDone (); + + case CERTIFICATE_VERIFY: + return new CertificateVerify (bodyBuffer, suite.signatureAlgorithm ()); + + case CLIENT_KEY_EXCHANGE: + return new ClientKeyExchange (bodyBuffer, suite, version); + + case FINISHED: + return new Finished (bodyBuffer, version); + + case CERTIFICATE_URL: + case CERTIFICATE_STATUS: + throw new UnsupportedOperationException ("FIXME"); + } + throw new IllegalArgumentException ("unknown handshake type " + type); + } + + /** + * Returns a subsequence of the underlying buffer, containing only + * the bytes that compose the handshake body. + * + * @return The body's byte buffer. + */ + public ByteBuffer bodyBuffer () + { + int length = length (); + return ((ByteBuffer) buffer.position (4).limit (4 + length)).slice (); + } + + /** + * Sets the handshake body type. + * + * @param type The handshake type. + */ + public void setType (final Type type) + { + buffer.put (0, (byte) type.getValue ()); + } + + /** + * Sets the length of the handshake body. + * + * @param length The handshake body length. + * @throws java.nio.ReadOnlyBufferException If the underlying buffer + * is not writable. + * @throws IllegalArgumentException of length is not + * between 0 and 16777215, inclusive. + */ + public void setLength (final int length) + { + if (length < 0 || length > 0xFFFFFF) + throw new IllegalArgumentException ("length " + length + " out of range;" + + " must be between 0 and 16777215"); + buffer.put (1, (byte) (length >>> 16)); + buffer.put (2, (byte) (length >>> 8)); + buffer.put (3, (byte) length); + } + + public String toString() + { + return toString (null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) out.print (prefix); + out.println("struct {"); + if (prefix != null) out.print (prefix); + out.print (" type: "); + out.print (type ()); + out.println (";"); + Body body = body (); + out.println (body.toString (prefix != null ? (prefix + " ") : " ")); + if (prefix != null) out.print (prefix); + out.print ("} Handshake;"); + return str.toString(); + } + + // Inner class. + // ------------------------------------------------------------------------- + + public static interface Body extends Constructed + { + int length (); + + String toString (String prefix); + } + + public static enum Type + { + HELLO_REQUEST ( 0), + CLIENT_HELLO ( 1), + SERVER_HELLO ( 2), + CERTIFICATE (11), + SERVER_KEY_EXCHANGE (12), + CERTIFICATE_REQUEST (13), + SERVER_HELLO_DONE (14), + CERTIFICATE_VERIFY (15), + CLIENT_KEY_EXCHANGE (16), + FINISHED (20), + CERTIFICATE_URL (21), + CERTIFICATE_STATUS (22); + + private final int value; + + private Type(int value) + { + this.value = value; + } + + // Class methods. + // ----------------------------------------------------------------------- + + /** + * Convert a raw handshake type value to a type enum value. + * + * @return The corresponding enum value for the raw integer value. + * @throws IllegalArgumentException If the value is not a known handshake + * type. + */ + public static Type forInteger (final int value) + { + switch (value & 0xFF) + { + case 0: return HELLO_REQUEST; + case 1: return CLIENT_HELLO; + case 2: return SERVER_HELLO; + case 11: return CERTIFICATE; + case 12: return SERVER_KEY_EXCHANGE; + case 13: return CERTIFICATE_REQUEST; + case 14: return SERVER_HELLO_DONE; + case 15: return CERTIFICATE_VERIFY; + case 16: return CLIENT_KEY_EXCHANGE; + case 20: return FINISHED; + case 21: return CERTIFICATE_URL; + case 22: return CERTIFICATE_STATUS; + default: throw new IllegalArgumentException ("unsupported value type " + value); + } + } + + public int getValue() + { + return value; + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/HelloRequest.java b/libjava/classpath/gnu/javax/net/ssl/provider/HelloRequest.java new file mode 100644 index 000000000..81dfce591 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/HelloRequest.java @@ -0,0 +1,72 @@ +/* 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; + +import gnu.java.lang.CPStringBuilder; + +/** + * 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) + { + CPStringBuilder str = new CPStringBuilder (); + 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/libjava/classpath/gnu/javax/net/ssl/provider/InputSecurityParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/InputSecurityParameters.java new file mode 100644 index 000000000..1d3da833a --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/InputSecurityParameters.java @@ -0,0 +1,334 @@ +/* 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.zip.DataFormatException; +import java.util.zip.Inflater; + +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/libjava/classpath/gnu/javax/net/ssl/provider/Jessie.java b/libjava/classpath/gnu/javax/net/ssl/provider/Jessie.java new file mode 100644 index 000000000..d3fb3a658 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Jessie.java @@ -0,0 +1,102 @@ +/* Jessie.java -- JESSIE's JSSE provider. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.Provider; + +/** + * This is the security provider for Jessie. It implements the following + * algorithms: + * + *
    + * {@link javax.net.ssl.SSLContext}.SSLv3
    + * {@link javax.net.ssl.SSLContext}.SSL
    + * {@link javax.net.ssl.SSLContext}.TLSv1
    + * {@link javax.net.ssl.SSLContext}.TLS
    + * {@link javax.net.ssl.KeyManagerFactory}.JessieX509
    + * {@link javax.net.ssl.TrustManagerFactory}.JessieX509
    + * {@link javax.net.ssl.TrustManagerFactory}.SRP
    + * 
    + * + */ +public class Jessie extends Provider +{ + private static final long serialVersionUID = -1; + + public static final String VERSION = "2.0.0"; + public static final double VERSION_DOUBLE = 2.0; + + public Jessie() + { + super("Jessie", VERSION_DOUBLE, + "Implementing TLSv1.1, with SSLv3, TLSv1.0 compatibility modes; " + + "X.509 Key Manager Factory; " + + "X.509 Trust Manager Factory; " + + "SSLv3 MD5 and SHA Mac."); + + AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + put("SSLContext.TLSv1.1", SSLContextImpl.class.getName()); + put("Alg.Alias.SSLContext.SSLv3", "TLSv1.1"); + put("Alg.Alias.SSLContext.TLSv1", "TLSv1.1"); + put("Alg.Alias.SSLContext.TLSv1.0", "TLSv1.1"); + put("Alg.Alias.SSLContext.TLS", "TLSv1.1"); + put("Alg.Alias.SSLContext.SSL", "TLSv1.1"); + + put("KeyManagerFactory.JessieX509", X509KeyManagerFactory.class.getName()); + put("TrustManagerFactory.JessieX509", X509TrustManagerFactory.class.getName()); + put("KeyManagerFactory.JessiePSK", PreSharedKeyManagerFactoryImpl.class.getName()); + //put("TrustManagerFactory.SRP", SRPTrustManagerFactory.class.getName()); + + put("Mac.SSLv3HMac-MD5", SSLv3HMacMD5Impl.class.getName()); + put("Mac.SSLv3HMac-SHA", SSLv3HMacSHAImpl.class.getName()); + + put("Signature.TLSv1.1-RSA", SSLRSASignatureImpl.class.getName()); + put("Alg.Alias.Signature.TLSv1-RSA", "TLSv1.1-RSA"); + put("Alg.Alias.Signature.SSLv3-RSA", "TLSv1.1-RSA"); + + return null; + } + }); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java b/libjava/classpath/gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java new file mode 100644 index 000000000..04416c5a5 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/MacAlgorithm.java b/libjava/classpath/gnu/javax/net/ssl/provider/MacAlgorithm.java new file mode 100644 index 000000000..cae0efbfa --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/MacException.java b/libjava/classpath/gnu/javax/net/ssl/provider/MacException.java new file mode 100644 index 000000000..b8c479fdb --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/MacException.java @@ -0,0 +1,53 @@ +/* MacException.java -- signals a bad record MAC. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.IOException; + +class MacException extends IOException +{ + + // Constructor. + // ------------------------------------------------------------------------- + + MacException() + { + super(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/MaxFragmentLength.java b/libjava/classpath/gnu/javax/net/ssl/provider/MaxFragmentLength.java new file mode 100644 index 000000000..acbfedff1 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/OutputSecurityParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/OutputSecurityParameters.java new file mode 100644 index 000000000..c6ed7d587 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/OutputSecurityParameters.java @@ -0,0 +1,294 @@ +/* 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.ByteBufferOutputStream; + +import java.nio.ByteBuffer; + +import java.util.zip.DataFormatException; +import java.util.zip.Deflater; + +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; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java new file mode 100644 index 000000000..16263fb37 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/ProtocolVersion.java b/libjava/classpath/gnu/javax/net/ssl/provider/ProtocolVersion.java new file mode 100644 index 000000000..3c3f29a21 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ProtocolVersion.java @@ -0,0 +1,200 @@ +/* ProtocolVersion.java -- An SSL version number. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.InputStream; +import java.io.IOException; + +public final class ProtocolVersion + implements Comparable, Constructed +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final ProtocolVersion SSL_3 = new ProtocolVersion(3, 0); + public static final ProtocolVersion TLS_1 = new ProtocolVersion(3, 1); + public static final ProtocolVersion TLS_1_1 = new ProtocolVersion(3, 2); + + private final int major; + private final int minor; + + // Constructor. + // ------------------------------------------------------------------------- + + private ProtocolVersion(int major, int minor) + { + this.major = major; + this.minor = minor; + } + + // Class methods. + // ------------------------------------------------------------------------- + + public static ProtocolVersion read(InputStream in) throws IOException + { + int major = in.read() & 0xFF; + int minor = in.read() & 0xFF; + return getInstance(major, minor); + } + + public static ProtocolVersion forName (final String name) + { + if (name.equalsIgnoreCase ("SSLv3")) + return SSL_3; + if (name.equalsIgnoreCase ("TLSv1")) + return TLS_1; + if (name.equalsIgnoreCase("TLSv1.1")) + return TLS_1_1; + throw new IllegalArgumentException ("unknown protocol name: " + name); + } + + public static ProtocolVersion getInstance(final int major, final int minor) + { + if (major == 3) + { + switch (minor) + { + case 0: return SSL_3; + case 1: return TLS_1; + case 2: return TLS_1_1; + } + } + return new ProtocolVersion(major, minor); + } + + public static ProtocolVersion getInstance (final short raw_value) + { + int major = raw_value >>> 8 & 0xFF; + int minor = raw_value & 0xFF; + return getInstance (major, minor); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public int length () + { + return 2; + } + + public byte[] getEncoded() + { + return new byte[] { + (byte) major, (byte) minor + }; + } + + public int major() + { + return major; + } + + public int minor() + { + return minor; + } + + public int rawValue () + { + return (major << 8) | minor; + } + + public boolean equals(Object o) + { + if (!(o instanceof ProtocolVersion)) + { + return false; + } + return ((ProtocolVersion) o).major == this.major + && ((ProtocolVersion) o).minor == this.minor; + } + + public int hashCode() + { + return major << 8 | minor; + } + + public int compareTo(ProtocolVersion that) + { + if (major > that.major) + { + return 1; + } + else if (major < that.major) + { + return -1; + } + + if (minor > that.minor) + { + return 1; + } + else if (minor < that.minor) + { + return -1; + } + return 0; + } + + public String toString (String prefix) + { + return toString (); + } + + public String toString() + { + if (this == SSL_3) + { + return "SSLv3"; + } + else if (this == TLS_1) + { + return "TLSv1"; + } + else if (this == TLS_1_1) + { + return "TLSv1.1"; + } + else + { + return "Unsupported; major=" + major + " minor=" + minor; + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Random.java b/libjava/classpath/gnu/javax/net/ssl/provider/Random.java new file mode 100644 index 000000000..bd5c037f5 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Random.java @@ -0,0 +1,150 @@ +/* Random.java -- SSL Random structure. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.PrintWriter; +import java.io.StringWriter; + +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.
    +  // -------------------------------------------------------------------------
    +
    +  static final int RANDOM_LENGTH = 28;
    +
    +  private final ByteBuffer buffer;
    +
    +  // Constructors.
    +  // -------------------------------------------------------------------------
    +
    +  public Random (final ByteBuffer buffer)
    +  {
    +    this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
    +  }
    +
    +  public Random copy()
    +  {
    +    ByteBuffer buffer = ByteBuffer.allocate(32);
    +    buffer.put((ByteBuffer) this.buffer.duplicate().position(0));
    +    return new Random(buffer);
    +  }
    +
    +  public int length()
    +  {
    +    return RANDOM_LENGTH + 4;
    +  }
    +
    +  public ByteBuffer buffer()
    +  {
    +    return ((ByteBuffer) buffer.duplicate().position(0).limit(length())).slice();
    +  }
    +
    +  public int gmtUnixTime ()
    +  {
    +    return buffer.getInt(0);
    +  }
    +
    +  public byte[] randomBytes()
    +  {
    +    byte[] buf = new byte[28];
    +    buffer.position (4);
    +    buffer.get (buf);
    +    return buf;
    +  }
    +
    +  public void setGmtUnixTime (final int gmtUnixTime)
    +  {
    +    buffer.putInt (0, gmtUnixTime);
    +  }
    +
    +  public void setRandomBytes (final byte[] randomBytes)
    +  {
    +    setRandomBytes (randomBytes, 0);
    +  }
    +
    +  public void setRandomBytes (final byte[] randomBytes, final int offset)
    +  {
    +    if (randomBytes.length - offset < RANDOM_LENGTH)
    +      throw new IllegalArgumentException ("random value too short");
    +    buffer.position (4);
    +    buffer.put (randomBytes, offset, RANDOM_LENGTH);
    +  }
    +
    +  public String toString (final String prefix)
    +  {
    +    StringWriter str = new StringWriter();
    +    PrintWriter out = new PrintWriter(str);
    +    if (prefix != null)
    +      out.print (prefix);
    +    out.println("struct {");
    +    if (prefix != null)
    +      out.print (prefix);
    +    out.print ("  gmt_unix_time: ");
    +    out.print (gmtUnixTime ());
    +    out.println (";");
    +    if (prefix != null)
    +      out.print (prefix);
    +    out.print ("  random_bytes:  ");
    +    out.print (Util.toHexString (randomBytes (), ':'));
    +    out.println (";");
    +    if (prefix != null)
    +      out.print (prefix);
    +    out.print ("} Random;");
    +    return str.toString();
    +  }
    +
    +  public String toString ()
    +  {
    +    return toString (null);
    +  }
    +}
    diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Record.java b/libjava/classpath/gnu/javax/net/ssl/provider/Record.java
    new file mode 100644
    index 000000000..6f5a23ef4
    --- /dev/null
    +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java b/libjava/classpath/gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java new file mode 100644 index 000000000..c5422871d --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java @@ -0,0 +1,223 @@ +/* SRPTrustManagerFactory.java -- trust manager for SRP. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.IOException; +import java.math.BigInteger; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyPair; +import java.security.KeyStore; +import java.util.HashMap; + +import javax.net.ssl.ManagerFactoryParameters; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactorySpi; + +import gnu.java.security.key.IKeyPairGenerator; +import gnu.javax.crypto.key.srp6.SRPKeyPairGenerator; +import gnu.javax.crypto.sasl.srp.PasswordFile; +import gnu.javax.crypto.sasl.srp.SRP; + +import gnu.javax.net.ssl.SRPManagerParameters; +import gnu.javax.net.ssl.SRPTrustManager; + +/** + * This is an implementation of a {@link javax.net.ssl.TrustManagerFactory} + * engine for the ``SRP'' algorithm. You must initialize instances of this + * algorithm with {@link SRPManagerParameters}. + */ +public class SRPTrustManagerFactory extends TrustManagerFactorySpi +{ + + // Field. + // ------------------------------------------------------------------------- + + private Manager current; + + // Constructor. + // ------------------------------------------------------------------------- + + public SRPTrustManagerFactory() + { + super(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + protected TrustManager[] engineGetTrustManagers() + { + if (current == null) + throw new IllegalStateException("not initialized"); + return new TrustManager[] { current }; + } + + protected void engineInit(KeyStore ks) + { + throw new IllegalArgumentException("only accepts SRPManagerParameters"); + } + + protected void engineInit(ManagerFactoryParameters params) + throws InvalidAlgorithmParameterException + { + if (params == null) + { + try + { + String srpPasswd = Util.getSecurityProperty("jessie.srp.password.file"); + if (srpPasswd == null) + { + current = new Manager(new PasswordFile()); + return; + } + String srpPasswd2 = Util.getSecurityProperty("jessie.srp.password.file2"); + if (srpPasswd2 == null) + srpPasswd2 = srpPasswd + "2"; + String srpConfig = Util.getSecurityProperty("jessie.srp.config"); + if (srpConfig == null) + srpConfig = srpPasswd + ".conf"; + current = new Manager(new PasswordFile(srpPasswd, srpPasswd2, srpConfig)); + return; + } + catch (IOException ioe) + { + throw new InvalidAlgorithmParameterException("default initialization failed: " + + ioe.toString()); + } + } + if (params instanceof SRPManagerParameters) + { + current = new Manager(((SRPManagerParameters) params).getPasswordFile()); + return; + } + throw new InvalidAlgorithmParameterException(); + } + + // Inner class. + // ------------------------------------------------------------------------- + + private class Manager implements SRPTrustManager + { + + // Field. + // ----------------------------------------------------------------------- + + private final PasswordFile file; + + // Constructor. + // ----------------------------------------------------------------------- + + Manager(PasswordFile file) + { + this.file = file; + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public boolean contains(String user) + { + try + { + return file.contains(user); + } + catch (IOException ioe) { } + return false; + } + + public KeyPair getKeyPair(String user) + { + try + { + if (file.contains(user)) + { + SRP srp = SRP.instance("SHA"); + String[] ent = file.lookup(user, "SHA"); + String[] cnf = file.lookupConfig(ent[2]); + BigInteger v, N, g; + v = new BigInteger(1, gnu.java.security.util.Util.fromBase64(ent[0])); + N = new BigInteger(1, gnu.java.security.util.Util.fromBase64(cnf[0])); + g = new BigInteger(1, gnu.java.security.util.Util.fromBase64(cnf[1])); + IKeyPairGenerator kpg = new SRPKeyPairGenerator(); + HashMap attr = new HashMap(); + attr.put(SRPKeyPairGenerator.SHARED_MODULUS, N); + attr.put(SRPKeyPairGenerator.GENERATOR, g); + attr.put(SRPKeyPairGenerator.USER_VERIFIER, v); + kpg.setup(attr); + return kpg.generate(); + } + } + catch (IOException ioe) { } + return null; + } + + public byte[] getSalt(String user) + { + try + { + if (file.contains(user)) + { + return gnu.java.security.util.Util.fromBase64(file.lookup(user, "SHA")[1]); + } + } + catch (IOException ioe) { } + return null; + } + + public BigInteger getVerifier(String user) + { + try + { + if (file.contains(user)) + { + return new BigInteger(1, + gnu.java.security.util.Util.fromBase64(file.lookup(user, "SHA")[0])); + } + } + catch (IOException ioe) { } + return null; + } + + public PasswordFile getPasswordFile() + { + return file; + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLContextImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLContextImpl.java new file mode 100644 index 000000000..50bbdb61b --- /dev/null +++ b/libjava/classpath/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; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLEngineImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLEngineImpl.java new file mode 100644 index 000000000..b63fb2f20 --- /dev/null +++ b/libjava/classpath/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; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLHMac.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLHMac.java new file mode 100644 index 000000000..002b3077f --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLHMac.java @@ -0,0 +1,158 @@ +/* SSLHMac.java -- SSLv3's MAC algorithm. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.util.Arrays; +import java.util.Map; + +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.javax.crypto.mac.IMac; + +/** + * The MAC function in SSLv3. This mac is defined as: + * + *
    + * hash(MAC_write_secret, pad_2 +
    + *      hash(MAC_write_secret + pad_1 + data));
    + * + *

    hash is e.g. MD5 or SHA-1, pad_1 is the value + * 0x36 48 times for MD5 and 40 times for SHA-1, and pad_2 is + * the value 0x5c repeated similarly. + */ +class SSLHMac implements IMac, Cloneable +{ + + // Fields. + // ------------------------------------------------------------------------- + + static final byte PAD1 = 0x36; + static final byte PAD2 = 0x5c; + + protected IMessageDigest md; + protected byte[] key; + protected final byte[] pad1, pad2; + + // Constructors. + // ------------------------------------------------------------------------- + + SSLHMac(String mdName) + { + super(); + this.md = HashFactory.getInstance(mdName); + if (mdName.equalsIgnoreCase("MD5")) + { + pad1 = new byte[48]; + pad2 = new byte[48]; + } + else + { + pad1 = new byte[40]; + pad2 = new byte[40]; + } + Arrays.fill(pad1, PAD1); + Arrays.fill(pad2, PAD2); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException cnse) + { + throw new Error(); + } + } + + public String name() + { + return "SSLHMac-" + md.name(); + } + + public int macSize() + { + return md.hashSize(); + } + + public void init(Map attributes) + { + key = (byte[]) attributes.get(MAC_KEY_MATERIAL); + if (key == null) + throw new NullPointerException(); + reset(); + } + + public void reset() + { + md.reset(); + md.update(key, 0, key.length); + md.update(pad1, 0, pad1.length); + } + + public byte[] digest() + { + byte[] h1 = md.digest(); + md.update(key, 0, key.length); + md.update(pad2, 0, pad2.length); + md.update(h1, 0, h1.length); + byte[] result = md.digest(); + reset(); + return result; + } + + public void update(byte b) + { + md.update(b); + } + + public void update(byte[] buf, int off, int len) + { + md.update(buf, off, len); + } + + public boolean selfTest() + { + return true; // XXX + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLRSASignatureImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLRSASignatureImpl.java new file mode 100644 index 000000000..105b4d5d7 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLRSASignatureImpl.java @@ -0,0 +1,234 @@ +/* SSLRSASignatureImpl.java -- SSL/TLS RSA implementation. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import gnu.classpath.debug.Component; +import gnu.classpath.debug.SystemLogger; +import gnu.java.security.sig.rsa.RSA; + +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.InvalidParameterException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SignatureException; +import java.security.SignatureSpi; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.util.Arrays; + +/** + * An implementation of of the RSA signature algorithm; this is an RSA + * encrypted MD5 hash followed by a SHA-1 hash. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class SSLRSASignatureImpl extends SignatureSpi +{ + private static final SystemLogger logger = SystemLogger.SYSTEM; + private RSAPublicKey pubkey; + private RSAPrivateKey privkey; + private final MessageDigest md5, sha; + private boolean initSign = false; + private boolean initVerify = false; + + public SSLRSASignatureImpl() throws NoSuchAlgorithmException + { + md5 = MessageDigest.getInstance("MD5"); + sha = MessageDigest.getInstance("SHA-1"); + } + + /* (non-Javadoc) + * @see java.security.SignatureSpi#engineInitVerify(java.security.PublicKey) + */ + @Override protected void engineInitVerify(PublicKey publicKey) + throws InvalidKeyException + { + try + { + pubkey = (RSAPublicKey) publicKey; + initVerify = true; + initSign = false; + privkey = null; + } + catch (ClassCastException cce) + { + throw new InvalidKeyException(cce); + } + } + + /* (non-Javadoc) + * @see java.security.SignatureSpi#engineInitSign(java.security.PrivateKey) + */ + @Override protected void engineInitSign(PrivateKey privateKey) + throws InvalidKeyException + { + try + { + privkey = (RSAPrivateKey) privateKey; + initSign = true; + initVerify = false; + pubkey = null; + } + catch (ClassCastException cce) + { + throw new InvalidKeyException(cce); + } + } + + /* (non-Javadoc) + * @see java.security.SignatureSpi#engineUpdate(byte) + */ + @Override protected void engineUpdate(byte b) throws SignatureException + { + if (!initSign && !initVerify) + throw new IllegalStateException("not initialized"); + if (Debug.DEBUG) + logger.log(Component.SSL_HANDSHAKE, "SSL/RSA update 0x{0}", + Util.formatInt(b & 0xFF, 16, 2)); + md5.update(b); + sha.update(b); + } + + /* (non-Javadoc) + * @see java.security.SignatureSpi#engineUpdate(byte[], int, int) + */ + @Override protected void engineUpdate(byte[] b, int off, int len) + throws SignatureException + { + if (!initSign && !initVerify) + throw new IllegalStateException("not initialized"); + if (Debug.DEBUG) + logger.log(Component.SSL_HANDSHAKE, "SSL/RSA update\n{0}", + Util.hexDump(b, off, len, ">> ")); + md5.update(b, off, len); + sha.update(b, off, len); + } + + /* (non-Javadoc) + * @see java.security.SignatureSpi#engineSign() + */ + @Override protected byte[] engineSign() throws SignatureException + { + // FIXME we need to add RSA blinding to this, somehow. + + if (!initSign) + throw new SignatureException("not initialized for signing"); + // Pad the hash results with RSA block type 1. + final int k = (privkey.getModulus().bitLength() + 7) >>> 3; + final byte[] d = Util.concat(md5.digest(), sha.digest()); + if (k - 11 < d.length) + throw new SignatureException("message too long"); + final byte[] eb = new byte[k]; + eb[0] = 0x00; + eb[1] = 0x01; + for (int i = 2; i < k - d.length - 1; i++) + eb[i] = (byte) 0xFF; + System.arraycopy(d, 0, eb, k - d.length, d.length); + BigInteger EB = new BigInteger(eb); + + // Private-key encrypt the padded hashes. + BigInteger EM = RSA.sign(privkey, EB); + return Util.trim(EM); + } + + /* (non-Javadoc) + * @see java.security.SignatureSpi#engineVerify(byte[]) + */ + @Override protected boolean engineVerify(byte[] sigBytes) + throws SignatureException + { + if (!initVerify) + throw new SignatureException("not initialized for verifying"); + + // Public-key decrypt the signature representative. + BigInteger EM = new BigInteger(1, (byte[]) sigBytes); + BigInteger EB = RSA.verify(pubkey, EM); + + // Unpad the decrypted message. + int i = 0; + final byte[] eb = EB.toByteArray(); + if (eb[0] == 0x00) + { + for (i = 0; i < eb.length && eb[i] == 0x00; i++) + ; + } + else if (eb[0] == 0x01) + { + for (i = 1; i < eb.length && eb[i] != 0x00; i++) + { + if (eb[i] != (byte) 0xFF) + { + throw new SignatureException("bad padding"); + } + } + i++; + } + else + { + throw new SignatureException("decryption failed"); + } + byte[] d1 = Util.trim(eb, i, eb.length - i); + byte[] d2 = Util.concat(md5.digest(), sha.digest()); + if (Debug.DEBUG) + logger.logv(Component.SSL_HANDSHAKE, "SSL/RSA d1:{0} d2:{1}", + Util.toHexString(d1, ':'), Util.toHexString(d2, ':')); + return Arrays.equals(d1, d2); + } + + /* (non-Javadoc) + * @see java.security.SignatureSpi#engineSetParameter(java.lang.String, java.lang.Object) + */ + @Override protected void engineSetParameter(String param, Object value) + throws InvalidParameterException + { + throw new InvalidParameterException("parameters not supported"); + } + + /* (non-Javadoc) + * @see java.security.SignatureSpi#engineGetParameter(java.lang.String) + */ + @Override protected Object engineGetParameter(String param) + throws InvalidParameterException + { + throw new InvalidParameterException("parameters not supported"); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLRandom.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLRandom.java new file mode 100644 index 000000000..0b28f1044 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLRandom.java @@ -0,0 +1,165 @@ +/* SSLRandom.java -- SSLv3 pseudo-random function. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.util.Map; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; + +class SSLRandom implements IRandom +{ + + // Fields. + // ------------------------------------------------------------------------- + + static final String SECRET = "jessie.sslprng.secret"; + static final String SEED = "jessie.sslprng.seed"; + + private final IMessageDigest md5, sha; + private byte[] secret; + private byte[] buffer; + private byte pad; + private byte[] seed; + private int idx; + + // Constructor. + // ------------------------------------------------------------------------- + + SSLRandom() + { + md5 = HashFactory.getInstance("MD5"); + sha = HashFactory.getInstance("SHA-1"); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void init(Map attrib) + { + secret = (byte[]) attrib.get(SECRET); + seed = (byte[]) attrib.get(SEED); + + if (secret == null || seed == null) + throw new NullPointerException(); + + pad = (byte) 'A'; + try { buffer = nextBlock(); } + catch (LimitReachedException cantHappen) { } + } + + public String name() + { + return "SSLRandom"; + } + + public Object clone() + { + throw new UnsupportedOperationException(); + } + + public byte nextByte() throws LimitReachedException + { + if (buffer == null) + throw new IllegalStateException(); + if (idx >= buffer.length) + buffer = nextBlock(); + return buffer[idx++]; + } + + public void nextBytes(byte[] buf, int off, int len) + throws LimitReachedException + { + if (buffer == null) + throw new IllegalStateException(); + if (buf == null) + throw new NullPointerException(); + if (off < 0 || len < 0 || off+len > buf.length) + throw new IndexOutOfBoundsException(); + int count = 0; + while (count < len) + { + if (idx >= buffer.length) + buffer = nextBlock(); + int l = Math.min(buffer.length-idx, len-count); + System.arraycopy(buffer, idx, buf, off+count, l); + count += l; + idx += l; + } + } + + public boolean selfTest() + { + return true; // XXX + } + + // For future versions of GNU Crypto. No-ops. + public void addRandomByte (byte b) + { + } + + public void addRandomBytes(byte[] buffer) { + addRandomBytes(buffer, 0, buffer.length); + } + + public void addRandomBytes (byte[] b, int i, int j) + { + } + + // Own methods. + // ------------------------------------------------------------------------- + + private byte[] nextBlock() throws LimitReachedException + { + int count = pad - 'A' + 1; + if (count > 26) + throw new LimitReachedException(); + for (int i = 0; i < count; i++) + sha.update(pad); + sha.update(secret, 0, secret.length); + sha.update(seed, 0, seed.length); + byte[] b = sha.digest(); + md5.update(secret, 0, secret.length); + md5.update(b, 0, b.length); + idx = 0; + pad++; + return md5.digest(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketFactoryImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketFactoryImpl.java new file mode 100644 index 000000000..67620d173 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketImpl.java new file mode 100644 index 000000000..5b07017f0 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketFactoryImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketFactoryImpl.java new file mode 100644 index 000000000..d5dd54bce --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketFactoryImpl.java @@ -0,0 +1,143 @@ +/* SSLSocketFactoryImpl.java -- + Copyright (C) 2006, 2007 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.UnknownHostException; + +import javax.net.ssl.SSLSocketFactory; + +/** + * @author Casey Marshall (csm@gnu.org) + */ +public class SSLSocketFactoryImpl extends SSLSocketFactory +{ + /** + * The SSLContextImpl that created us. + */ + private final SSLContextImpl contextImpl; + + public SSLSocketFactoryImpl(SSLContextImpl contextImpl) + { + this.contextImpl = contextImpl; + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocketFactory#createSocket(java.net.Socket, java.lang.String, int, boolean) + */ + @Override public Socket createSocket(Socket socket, String host, int port, + boolean autoClose) + throws IOException + { + return new SSLSocketImpl(contextImpl, host, port, socket, autoClose); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocketFactory#getDefaultCipherSuites() + */ + @Override public String[] getDefaultCipherSuites() + { + return SSLEngineImpl.defaultSuites(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocketFactory#getSupportedCipherSuites() + */ + @Override public String[] getSupportedCipherSuites() + { + return CipherSuite.availableSuiteNames().toArray(new String[0]); + } + + /* (non-Javadoc) + * @see javax.net.SocketFactory#createSocket(java.lang.String, int) + */ + @Override public SSLSocketImpl createSocket(String host, int port) + throws IOException, UnknownHostException + { + return createSocket(host, port, null, 0); + } + + /* (non-Javadoc) + * @see javax.net.SocketFactory#createSocket(java.lang.String, int, java.net.InetAddress, int) + */ + @Override public SSLSocketImpl createSocket(String host, int port, + InetAddress localHost, int localPort) + throws IOException, UnknownHostException + { + SSLSocketImpl socket = new SSLSocketImpl(contextImpl, host, port); + InetSocketAddress endpoint = new InetSocketAddress(host, port); + socket.bind(new InetSocketAddress(localHost, localPort)); + socket.connect(endpoint); + return socket; + } + + /* (non-Javadoc) + * @see javax.net.SocketFactory#createSocket(java.net.InetAddress, int) + */ + @Override public SSLSocketImpl createSocket(InetAddress host, int port) + throws IOException + { + return createSocket(host, port, null, 0); + } + + /* (non-Javadoc) + * @see javax.net.SocketFactory#createSocket(java.net.InetAddress, int, java.net.InetAddress, int) + */ + @Override public SSLSocketImpl createSocket(InetAddress host, int port, + InetAddress localHost, int localPort) + throws IOException + { + SSLSocketImpl socket = new SSLSocketImpl(contextImpl, + host.getCanonicalHostName(), port); + socket.bind(new InetSocketAddress(localHost, localPort)); + socket.connect(new InetSocketAddress(host, port)); + return socket; + } + + /* (non-Javadoc) + * @see javax.net.SocketFactory#createSocket() + */ + @Override public Socket createSocket() throws IOException + { + return new SSLSocketImpl(contextImpl, null, -1, new Socket(), true); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketImpl.java new file mode 100644 index 000000000..9072c2886 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketImpl.java @@ -0,0 +1,740 @@ +/* SSLSocketImpl.java -- implementation of an SSL client socket. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import gnu.classpath.debug.Component; +import gnu.classpath.debug.SystemLogger; + +import java.io.DataInputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketException; +import java.nio.ByteBuffer; +import java.nio.channels.SocketChannel; +import java.util.HashSet; +import java.util.Set; + +import javax.net.ssl.HandshakeCompletedEvent; +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.SSLEngineResult; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLEngineResult.HandshakeStatus; +import javax.net.ssl.SSLEngineResult.Status; + +/** + * @author Casey Marshall (csm@gnu.org) + */ +public class SSLSocketImpl extends SSLSocket +{ + private class SocketOutputStream extends OutputStream + { + private final ByteBuffer buffer; + private final OutputStream out; + + SocketOutputStream() throws IOException + { + buffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]); + if (underlyingSocket != null) + out = underlyingSocket.getOutputStream(); + else + out = SSLSocketImpl.super.getOutputStream(); + } + + @Override public void write(byte[] buf, int off, int len) throws IOException + { + if (!initialHandshakeDone + || engine.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING) + { + doHandshake(); + if (handshakeException != null) + throw handshakeException; + } + + int k = 0; + while (k < len) + { + synchronized (engine) + { + int l = Math.min(len-k, getSession().getApplicationBufferSize()); + ByteBuffer in = ByteBuffer.wrap(buf, off+k, l); + SSLEngineResult result = engine.wrap(in, buffer); + if (result.getStatus() == Status.CLOSED) + return; + if (result.getStatus() != Status.OK) + throw new SSLException("unexpected SSL state " + result.getStatus()); + buffer.flip(); + out.write(buffer.array(), 0, buffer.limit()); + k += result.bytesConsumed(); + buffer.clear(); + } + } + } + + @Override public void write(int b) throws IOException + { + write(new byte[] { (byte) b }); + } + + @Override public void close() throws IOException + { + SSLSocketImpl.this.close(); + } + } + + private class SocketInputStream extends InputStream + { + private final ByteBuffer inBuffer; + private final ByteBuffer appBuffer; + private final DataInputStream in; + + SocketInputStream() throws IOException + { + inBuffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]); + inBuffer.limit(0); + appBuffer = ByteBuffer.allocate(getSession().getApplicationBufferSize()); + appBuffer.flip(); + if (underlyingSocket != null) + in = new DataInputStream(underlyingSocket.getInputStream()); + else + in = new DataInputStream(SSLSocketImpl.super.getInputStream()); + } + + @Override public int read(byte[] buf, int off, int len) throws IOException + { + if (!initialHandshakeDone || + engine.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING) + { + doHandshake(); + if (handshakeException != null) + throw handshakeException; + } + + if (!appBuffer.hasRemaining()) + { + int x = in.read(); + if (x == -1) + return -1; + inBuffer.clear(); + inBuffer.put((byte) x); + inBuffer.putInt(in.readInt()); + int reclen = inBuffer.getShort(3) & 0xFFFF; + in.readFully(inBuffer.array(), 5, reclen); + inBuffer.position(0).limit(reclen + 5); + synchronized (engine) + { + appBuffer.clear(); + SSLEngineResult result = engine.unwrap(inBuffer, appBuffer); + Status status = result.getStatus(); + if (status == Status.CLOSED && result.bytesProduced() == 0) + return -1; + } + inBuffer.compact(); + appBuffer.flip(); + } + int l = Math.min(len, appBuffer.remaining()); + appBuffer.get(buf, off, l); + return l; + } + + @Override public int read() throws IOException + { + byte[] b = new byte[1]; + if (read(b) == -1) + return -1; + return b[0] & 0xFF; + } + } + + private static final SystemLogger logger = SystemLogger.getSystemLogger(); + + private SSLEngineImpl engine; + private Set listeners; + private Socket underlyingSocket; + private boolean isHandshaking; + private IOException handshakeException; + private boolean initialHandshakeDone = false; + private final boolean autoClose; + + public SSLSocketImpl(SSLContextImpl contextImpl, String host, int port) + { + this(contextImpl, host, port, new Socket(), true); + } + + public SSLSocketImpl(SSLContextImpl contextImpl, String host, int port, + Socket underlyingSocket, boolean autoClose) + { + engine = new SSLEngineImpl(contextImpl, host, port); + engine.setUseClientMode(true); // default to client mode + listeners = new HashSet(); + this.underlyingSocket = underlyingSocket; + this.autoClose = autoClose; + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#addHandshakeCompletedListener(javax.net.ssl.HandshakeCompletedListener) + */ + @Override + public void addHandshakeCompletedListener(HandshakeCompletedListener listener) + { + listeners.add(listener); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#getEnableSessionCreation() + */ + @Override public boolean getEnableSessionCreation() + { + return engine.getEnableSessionCreation(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#getEnabledCipherSuites() + */ + @Override public String[] getEnabledCipherSuites() + { + return engine.getEnabledCipherSuites(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#getEnabledProtocols() + */ + @Override public String[] getEnabledProtocols() + { + return engine.getEnabledProtocols(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#getNeedClientAuth() + */ + @Override public boolean getNeedClientAuth() + { + return engine.getNeedClientAuth(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#getSession() + */ + @Override public SSLSession getSession() + { + return engine.getSession(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#getSupportedCipherSuites() + */ + @Override public String[] getSupportedCipherSuites() + { + return engine.getSupportedCipherSuites(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#getSupportedProtocols() + */ + @Override public String[] getSupportedProtocols() + { + return engine.getSupportedProtocols(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#getUseClientMode() + */ + @Override public boolean getUseClientMode() + { + return engine.getUseClientMode(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#getWantClientAuth() + */ + @Override public boolean getWantClientAuth() + { + return engine.getWantClientAuth(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#removeHandshakeCompletedListener(javax.net.ssl.HandshakeCompletedListener) + */ + @Override + public void removeHandshakeCompletedListener(HandshakeCompletedListener listener) + { + listeners.remove(listener); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#setEnableSessionCreation(boolean) + */ + @Override public void setEnableSessionCreation(boolean enable) + { + engine.setEnableSessionCreation(enable); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#setEnabledCipherSuites(java.lang.String[]) + */ + @Override public void setEnabledCipherSuites(String[] suites) + { + engine.setEnabledCipherSuites(suites); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#setEnabledProtocols(java.lang.String[]) + */ + @Override public void setEnabledProtocols(String[] protocols) + { + engine.setEnabledProtocols(protocols); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#setNeedClientAuth(boolean) + */ + @Override public void setNeedClientAuth(boolean needAuth) + { + engine.setNeedClientAuth(needAuth); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#setUseClientMode(boolean) + */ + @Override public void setUseClientMode(boolean clientMode) + { + engine.setUseClientMode(clientMode); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#setWantClientAuth(boolean) + */ + @Override public void setWantClientAuth(boolean wantAuth) + { + engine.setWantClientAuth(wantAuth); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#startHandshake() + */ + @Override public void startHandshake() throws IOException + { + if (isHandshaking) + return; + + if (handshakeException != null) + throw handshakeException; + + Thread t = new Thread(new Runnable() + { + public void run() + { + try + { + doHandshake(); + } + catch (IOException ioe) + { + handshakeException = ioe; + } + } + }, "HandshakeThread@" + System.identityHashCode(this)); + t.start(); + } + + void doHandshake() throws IOException + { + synchronized (engine) + { + if (isHandshaking) + { + try + { + engine.wait(); + } + catch (InterruptedException ie) + { + } + return; + } + isHandshaking = true; + } + + if (initialHandshakeDone) + throw new SSLException("rehandshaking not yet implemented"); + + long now = -System.currentTimeMillis(); + engine.beginHandshake(); + + HandshakeStatus status = engine.getHandshakeStatus(); + assert(status != HandshakeStatus.NOT_HANDSHAKING); + + ByteBuffer inBuffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]); + inBuffer.position(inBuffer.limit()); + ByteBuffer outBuffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]); + ByteBuffer emptyBuffer = ByteBuffer.allocate(0); + SSLEngineResult result = null; + + DataInputStream sockIn = new DataInputStream(underlyingSocket.getInputStream()); + OutputStream sockOut = underlyingSocket.getOutputStream(); + + try + { + while (status != HandshakeStatus.NOT_HANDSHAKING + && status != HandshakeStatus.FINISHED) + { + logger.logv(Component.SSL_HANDSHAKE, "socket processing state {0}", + status); + + if (inBuffer.capacity() != getSession().getPacketBufferSize()) + { + ByteBuffer b + = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]); + if (inBuffer.hasRemaining()) + b.put(inBuffer).flip(); + inBuffer = b; + } + if (outBuffer.capacity() != getSession().getPacketBufferSize()) + outBuffer + = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]); + + switch (status) + { + case NEED_UNWRAP: + // Read in a single SSL record. + inBuffer.clear(); + int i = sockIn.read(); + if (i == -1) + throw new EOFException(); + if ((i & 0x80) == 0x80) // SSLv2 client hello. + { + inBuffer.put((byte) i); + int v2len = (i & 0x7f) << 8; + i = sockIn.read(); + v2len = v2len | (i & 0xff); + inBuffer.put((byte) i); + sockIn.readFully(inBuffer.array(), 2, v2len); + inBuffer.position(0).limit(v2len + 2); + } + else + { + inBuffer.put((byte) i); + inBuffer.putInt(sockIn.readInt()); + int reclen = inBuffer.getShort(3) & 0xFFFF; + sockIn.readFully(inBuffer.array(), 5, reclen); + inBuffer.position(0).limit(reclen + 5); + } + result = engine.unwrap(inBuffer, emptyBuffer); + status = result.getHandshakeStatus(); + if (result.getStatus() != Status.OK) + throw new SSLException("unexpected SSL status " + + result.getStatus()); + break; + + case NEED_WRAP: + { + outBuffer.clear(); + result = engine.wrap(emptyBuffer, outBuffer); + status = result.getHandshakeStatus(); + if (result.getStatus() != Status.OK) + throw new SSLException("unexpected SSL status " + + result.getStatus()); + outBuffer.flip(); + sockOut.write(outBuffer.array(), outBuffer.position(), + outBuffer.limit()); + } + break; + + case NEED_TASK: + { + Runnable task; + while ((task = engine.getDelegatedTask()) != null) + task.run(); + status = engine.getHandshakeStatus(); + } + break; + + case FINISHED: + break; + } + } + + initialHandshakeDone = true; + + HandshakeCompletedEvent hce = new HandshakeCompletedEvent(this, getSession()); + for (HandshakeCompletedListener l : listeners) + { + try + { + l.handshakeCompleted(hce); + } + catch (ThreadDeath td) + { + throw td; + } + catch (Throwable x) + { + logger.log(Component.WARNING, + "HandshakeCompletedListener threw exception", x); + } + } + + now += System.currentTimeMillis(); + if (Debug.DEBUG) + logger.logv(Component.SSL_HANDSHAKE, + "handshake completed in {0}ms in thread {1}", now, + Thread.currentThread().getName()); + } + catch (SSLException ssle) + { + handshakeException = ssle; + throw ssle; + } + finally + { + synchronized (engine) + { + isHandshaking = false; + engine.notifyAll(); + } + } + } + + // Methods overriding Socket. + + @Override public void bind(SocketAddress bindpoint) throws IOException + { + underlyingSocket.bind(bindpoint); + } + + @Override public void connect(SocketAddress endpoint) throws IOException + { + underlyingSocket.connect(endpoint); + } + + @Override public void connect(SocketAddress endpoint, int timeout) + throws IOException + { + underlyingSocket.connect(endpoint, timeout); + } + + @Override public InetAddress getInetAddress() + { + return underlyingSocket.getInetAddress(); + } + + @Override public InetAddress getLocalAddress() + { + return underlyingSocket.getLocalAddress(); + } + + @Override public int getPort() + { + return underlyingSocket.getPort(); + } + + @Override public int getLocalPort() + { + return underlyingSocket.getLocalPort(); + } + + @Override public SocketAddress getRemoteSocketAddress() + { + return underlyingSocket.getRemoteSocketAddress(); + } + + public SocketAddress getLocalSocketAddress() + { + return underlyingSocket.getLocalSocketAddress(); + } + + @Override public SocketChannel getChannel() + { + throw new UnsupportedOperationException("use javax.net.ssl.SSLEngine for NIO"); + } + + @Override public InputStream getInputStream() throws IOException + { + return new SocketInputStream(); + } + + @Override public OutputStream getOutputStream() throws IOException + { + return new SocketOutputStream(); + } + + @Override public void setTcpNoDelay(boolean on) throws SocketException + { + underlyingSocket.setTcpNoDelay(on); + } + + @Override public boolean getTcpNoDelay() throws SocketException + { + return underlyingSocket.getTcpNoDelay(); + } + + @Override public void setSoLinger(boolean on, int linger) throws SocketException + { + underlyingSocket.setSoLinger(on, linger); + } + + public int getSoLinger() throws SocketException + { + return underlyingSocket.getSoLinger(); + } + + @Override public void sendUrgentData(int x) throws IOException + { + throw new UnsupportedOperationException("not supported"); + } + + @Override public void setOOBInline(boolean on) throws SocketException + { + underlyingSocket.setOOBInline(on); + } + + @Override public boolean getOOBInline() throws SocketException + { + return underlyingSocket.getOOBInline(); + } + + @Override public void setSoTimeout(int timeout) throws SocketException + { + underlyingSocket.setSoTimeout(timeout); + } + + @Override public int getSoTimeout() throws SocketException + { + return underlyingSocket.getSoTimeout(); + } + + @Override public void setSendBufferSize(int size) throws SocketException + { + underlyingSocket.setSendBufferSize(size); + } + + @Override public int getSendBufferSize() throws SocketException + { + return underlyingSocket.getSendBufferSize(); + } + + @Override public void setReceiveBufferSize(int size) throws SocketException + { + underlyingSocket.setReceiveBufferSize(size); + } + + @Override public int getReceiveBufferSize() throws SocketException + { + return underlyingSocket.getReceiveBufferSize(); + } + + @Override public void setKeepAlive(boolean on) throws SocketException + { + underlyingSocket.setKeepAlive(on); + } + + @Override public boolean getKeepAlive() throws SocketException + { + return underlyingSocket.getKeepAlive(); + } + + @Override public void setTrafficClass(int tc) throws SocketException + { + underlyingSocket.setTrafficClass(tc); + } + + @Override public int getTrafficClass() throws SocketException + { + return underlyingSocket.getTrafficClass(); + } + + @Override public void setReuseAddress(boolean reuseAddress) + throws SocketException + { + underlyingSocket.setReuseAddress(reuseAddress); + } + + @Override public boolean getReuseAddress() throws SocketException + { + return underlyingSocket.getReuseAddress(); + } + + @Override public void close() throws IOException + { + // XXX closure alerts. + if (autoClose) + underlyingSocket.close(); + } + + @Override public void shutdownInput() throws IOException + { + underlyingSocket.shutdownInput(); + } + + @Override public void shutdownOutput() throws IOException + { + underlyingSocket.shutdownOutput(); + } + + @Override public boolean isConnected() + { + return underlyingSocket.isConnected(); + } + + @Override public boolean isBound() + { + return underlyingSocket.isBound(); + } + + @Override public boolean isClosed() + { + return underlyingSocket.isClosed(); + } + + @Override public boolean isInputShutdown() + { + return underlyingSocket.isInputShutdown(); + } + + @Override public boolean isOutputShutdown() + { + return underlyingSocket.isOutputShutdown(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacMD5Impl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacMD5Impl.java new file mode 100644 index 000000000..5ef84ca1c --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacSHAImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacSHAImpl.java new file mode 100644 index 000000000..6b9c9e9cc --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java new file mode 100644 index 000000000..1de3f8124 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java @@ -0,0 +1,148 @@ +/* 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 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/libjava/classpath/gnu/javax/net/ssl/provider/ServerDHParams.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerDHParams.java new file mode 100644 index 000000000..0e2c34881 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/ServerHandshake.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHandshake.java new file mode 100644 index 000000000..d69fa120d --- /dev/null +++ b/libjava/classpath/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); + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerHello.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHello.java new file mode 100644 index 000000000..944194b3e --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHello.java @@ -0,0 +1,231 @@ +/* ServerHello.java -- SSL ServerHello message. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.PrintWriter; +import java.io.StringWriter; + +import java.nio.ByteBuffer; + +/** + * The server hello message. + * + *
    +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. + // ------------------------------------------------------------------------- + + protected static final int RANDOM_OFFSET = 2; + protected static final int SESSID_OFFSET = 32 + RANDOM_OFFSET; + protected static final int SESSID_OFFSET2 = SESSID_OFFSET + 1; + + protected ByteBuffer buffer; + protected boolean disableExtensions; + + // Constructor. + // ------------------------------------------------------------------------- + + public ServerHello (final ByteBuffer buffer) + { + this.buffer = buffer; + disableExtensions = false; + } + + public int length () + { + int sessionLen = buffer.get(SESSID_OFFSET) & 0xFF; + int len = SESSID_OFFSET2 + sessionLen + 3; + int elen = 0; + if (!disableExtensions && len + 1 < buffer.limit() + && (elen = buffer.getShort(len)) != 0) + len += 2 + elen; + return len; + } + + /** + * Returns the server's protocol version. This will read two bytes + * from the beginning of the underlying buffer, and return an + * instance of the appropriate {@link ProtocolVersion}; if the + * version read is a supported version, this method returns a static + * constant instance. + * + * @return The server's protocol version. + */ + public ProtocolVersion version() + { + return ProtocolVersion.getInstance (buffer.getShort (0)); + } + + /** + * Returns the server's random value. This method returns a + * lightwieght wrapper around the existing bytes; modifications to + * the underlying buffer will modify the returned object, and + * vice-versa. + * + * @return The server's random value. + */ + public Random random() + { + ByteBuffer randomBuf = + ((ByteBuffer) buffer.duplicate ().position (RANDOM_OFFSET) + .limit (SESSID_OFFSET)).slice (); + return new Random (randomBuf); + } + + /** + * Returns the session ID. This method returns a new byte array with + * the session ID bytes. + * + * @return The session ID. + */ + public byte[] sessionId() + { + int idlen = buffer.get (SESSID_OFFSET) & 0xFF; + byte[] sessionId = new byte[idlen]; + buffer.position (SESSID_OFFSET2); + buffer.get (sessionId); + return sessionId; + } + + /** + * Returns the server's chosen cipher suite. The returned cipher + * suite will be "resolved" to this structure's version. + * + * @return The server's chosen cipher suite. + */ + public CipherSuite cipherSuite() + { + int offset = SESSID_OFFSET2 + (buffer.get(SESSID_OFFSET) & 0xFF); + return CipherSuite.forValue(buffer.getShort(offset)).resolve(); + } + + /** + * Returns the server's chosen compression method. + * + * @return The chosen compression method. + */ + public CompressionMethod compressionMethod() + { + int offset = SESSID_OFFSET2 + (buffer.get(SESSID_OFFSET) & 0xFF) + 2; + return CompressionMethod.getInstance(buffer.get(offset) & 0xFF); + } + + public int extensionsLength() + { + int offset = SESSID_OFFSET2 + (buffer.get (SESSID_OFFSET) & 0xFF) + 3; + if (offset + 1 >= buffer.limit()) + return 0; + return buffer.getShort(offset) & 0xFFFF; + } + + public ExtensionList extensions () + { + int offset = SESSID_OFFSET2 + (buffer.get (SESSID_OFFSET) & 0xFF) + 3; + if (offset + 1 >= buffer.limit()) + return null; + int len = buffer.getShort(offset) & 0xFFFF; + if (len == 0) + len = buffer.limit() - offset - 2; + ByteBuffer ebuf = ((ByteBuffer) buffer.duplicate().position(offset) + .limit(offset + len + 2)).slice(); + return new ExtensionList(ebuf); + } + + public String toString() + { + return toString(null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) + out.print (prefix); + out.println ("struct {"); + String subprefix = " "; + if (prefix != null) + subprefix += prefix; + out.print (subprefix); + out.print ("version: "); + out.print (version ()); + out.println (";"); + out.print (subprefix); + out.println ("random:"); + out.println (random ().toString (subprefix)); + out.print (subprefix); + out.print ("sessionId: "); + out.print (Util.toHexString(sessionId (), ':')); + out.println (";"); + out.print (subprefix); + out.print ("cipherSuite: "); + out.print (cipherSuite ()); + out.println (";"); + out.print (subprefix); + out.print ("compressionMethod: "); + out.print (compressionMethod ()); + out.println (";"); + ExtensionList exts = extensions (); + out.print (subprefix); + out.println ("extensions:"); + out.println (exts != null ? exts.toString (subprefix+" ") + : subprefix + " (nil)"); + if (prefix != null) + out.print (prefix); + out.print ("} ServerHello;"); + return str.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloBuilder.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloBuilder.java new file mode 100644 index 000000000..47bce29ee --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloDone.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloDone.java new file mode 100644 index 000000000..987b51c56 --- /dev/null +++ b/libjava/classpath/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;"); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchange.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchange.java new file mode 100644 index 000000000..1206ae6b2 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchange.java @@ -0,0 +1,173 @@ +/* ServerKeyExchange.java -- SSL ServerKeyExchange message. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.PrintWriter; +import java.io.StringWriter; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * The server key exchange message. + * + *
    +struct
    +{
    +  select (KeyExchangeAlgorithm)
    +  {
    +    case diffie_hellman:
    +      ServerDHParams params;
    +      Signature signed_params;
    +    case rsa:
    +      ServerRSAParams params;
    +      Signature signed_params;
    +    case srp:
    +      ServerSRPParams params;
    +      Signature signed_params;
    +  };
    +} ServerKeyExchange;
    +
    + */ +public class ServerKeyExchange implements Handshake.Body +{ + + protected ByteBuffer buffer; + protected final CipherSuite suite; + + public ServerKeyExchange(final ByteBuffer buffer, final CipherSuite suite) + { + suite.getClass(); + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); + this.suite = suite; + } + + public int length () + { + if (suite.keyExchangeAlgorithm ().equals (KeyExchangeAlgorithm.NONE)) + return 0; + int len = 0; + ServerKeyExchangeParams params = params(); + Signature sig = signature(); + if (params != null) + len += params.length(); + if (sig != null) + len += sig.length(); + return len; + } + + /** + * Returns the server's key exchange parameters. The value returned will + * depend on the key exchange algorithm this object was created with. + * + * @return The server's key exchange parameters. + */ + public ServerKeyExchangeParams params () + { + KeyExchangeAlgorithm kex = suite.keyExchangeAlgorithm (); + if (kex == KeyExchangeAlgorithm.RSA) + return new ServerRSAParams(buffer.duplicate ()); + else if (kex == KeyExchangeAlgorithm.DHE_DSS + || kex == KeyExchangeAlgorithm.DHE_RSA + || kex == KeyExchangeAlgorithm.DH_anon) + return new ServerDHParams(buffer.duplicate()); +// else if (kex.equals (KeyExchangeAlgorithm.SRP)) +// return new ServerSRPParams (buffer.duplicate ()); + else if (kex == KeyExchangeAlgorithm.NONE) + return null; + else if (kex == KeyExchangeAlgorithm.DHE_PSK) + return new ServerDHE_PSKParameters(buffer.duplicate()); + else if (kex == KeyExchangeAlgorithm.PSK) + return new ServerPSKParameters(buffer.duplicate()); + else if (kex == KeyExchangeAlgorithm.RSA_PSK) + return new ServerPSKParameters(buffer.duplicate()); + throw new IllegalArgumentException ("unsupported key exchange: " + kex); + } + + /** + * Returns the digital signature made over the key exchange parameters. + * + * @return The signature. + */ + public Signature signature () + { + KeyExchangeAlgorithm kex = suite.keyExchangeAlgorithm(); + if (kex == KeyExchangeAlgorithm.NONE + || kex == KeyExchangeAlgorithm.DH_anon + || kex == KeyExchangeAlgorithm.DHE_PSK + || kex == KeyExchangeAlgorithm.PSK + || kex == KeyExchangeAlgorithm.RSA_PSK) + return null; + ServerKeyExchangeParams params = params(); + ByteBuffer sigbuf = ((ByteBuffer) buffer.position(params.length ())).slice (); + return new Signature (sigbuf, suite.signatureAlgorithm ()); + } + + public String toString() + { + return toString (null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) out.print (prefix); + out.println("struct {"); + if (prefix != null) out.print (prefix); + out.print (" algorithm: "); + out.print (suite.keyExchangeAlgorithm ()); + out.println (";"); + if (!suite.keyExchangeAlgorithm ().equals (KeyExchangeAlgorithm.NONE)) + { + if (prefix != null) out.print (prefix); + out.println (" parameters:"); + out.println (params ().toString (prefix != null ? prefix+" " : " ")); + } + if (!suite.signatureAlgorithm ().equals (SignatureAlgorithm.ANONYMOUS)) + { + if (prefix != null) out.print (prefix); + out.println (" signature:"); + out.println (signature ().toString (prefix != null ? prefix+" " : " ")); + } + if (prefix != null) out.print (prefix); + out.print ("} ServerKeyExchange;"); + return str.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeBuilder.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeBuilder.java new file mode 100644 index 000000000..658ae228a --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeParams.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeParams.java new file mode 100644 index 000000000..cb523650f --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/ServerNameList.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerNameList.java new file mode 100644 index 000000000..38f092476 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/ServerPSKParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerPSKParameters.java new file mode 100644 index 000000000..9ecedb513 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/ServerRSAParams.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerRSAParams.java new file mode 100644 index 000000000..ff265ce8a --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java new file mode 100644 index 000000000..0895afe96 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/SessionImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SessionImpl.java new file mode 100644 index 000000000..6eb070efc --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SessionImpl.java @@ -0,0 +1,192 @@ +/* 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 java.io.IOException; +import java.io.Serializable; + +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SealedObject; +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/libjava/classpath/gnu/javax/net/ssl/provider/Signature.java b/libjava/classpath/gnu/javax/net/ssl/provider/Signature.java new file mode 100644 index 000000000..160dd805f --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Signature.java @@ -0,0 +1,157 @@ +/* Signature.java -- SSL Signature structure. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.PrintWriter; +import java.io.StringWriter; + +import java.nio.ByteBuffer; + +/** + * 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 ByteBuffer buffer; + private final SignatureAlgorithm alg; + + // Constructor. + // ------------------------------------------------------------------------- + + public Signature (final ByteBuffer buffer, final SignatureAlgorithm alg) + { + this.buffer = buffer; + this.alg = alg; + } + + public Signature (final byte[] sigValue, final SignatureAlgorithm alg) + { + buffer = ByteBuffer.allocate(sigValue.length + 2); + buffer.putShort((short) sigValue.length); + buffer.put(sigValue); + buffer.position(0); + this.alg = alg; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public int length () + { + if (alg.equals (SignatureAlgorithm.ANONYMOUS)) + return 0; + return (buffer.getShort (0) & 0xFFFF) + 2; + } + + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().limit(length()); + } + + public byte[] signature () + { + if (alg.equals (SignatureAlgorithm.ANONYMOUS)) + return new byte[0]; + int length = buffer.getShort (0) & 0xFFFF; + byte[] buf = new byte[length]; + ((ByteBuffer) buffer.duplicate().position(2)).get(buf); + return buf; + } + + public void setSignature (final byte[] signature) + { + setSignature (signature, 0, signature.length); + } + + public void setSignature (final byte[] signature, final int offset, final int length) + { + if (alg.equals (SignatureAlgorithm.ANONYMOUS)) + return; + buffer.putShort (0, (short) length); + buffer.position (2); + buffer.put (signature, offset, length); + } + + public String toString () + { + return toString (null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) + out.print (prefix); + out.println("struct {"); + if (!alg.equals (SignatureAlgorithm.ANONYMOUS)) + { + String subprefix = " "; + if (prefix != null) + subprefix = prefix + subprefix; + out.print (Util.hexDump (signature (), subprefix)); + } + if (prefix != null) + out.print (prefix); + out.print ("} Signature;"); + return str.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SignatureAlgorithm.java b/libjava/classpath/gnu/javax/net/ssl/provider/SignatureAlgorithm.java new file mode 100644 index 000000000..79cff5626 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/SimpleSessionContext.java b/libjava/classpath/gnu/javax/net/ssl/provider/SimpleSessionContext.java new file mode 100644 index 000000000..8d5745061 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SimpleSessionContext.java @@ -0,0 +1,144 @@ +/* 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 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/libjava/classpath/gnu/javax/net/ssl/provider/TLSHMac.java b/libjava/classpath/gnu/javax/net/ssl/provider/TLSHMac.java new file mode 100644 index 000000000..8bdda930b --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/TLSHMac.java @@ -0,0 +1,137 @@ +/* TLSHMac.java -- HMAC used in TLS. + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.security.InvalidKeyException; +import java.util.Map; + +import gnu.java.security.hash.IMessageDigest; +import gnu.javax.crypto.mac.HMac; + +/** + * The operation of this HMac is identical to normal HMacs, but this one + * allows keys with short lengths (including zero). + */ +class TLSHMac extends HMac +{ + + // Constants. + // ------------------------------------------------------------------------- + + private static final byte IPAD_BYTE = 0x36; + private static final byte OPAD_BYTE = 0x5C; + + // Constructor. + // ------------------------------------------------------------------------- + + TLSHMac(IMessageDigest hash) + { + super(hash); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void init(Map attributes) + throws InvalidKeyException, IllegalStateException + { + Integer ts = (Integer) attributes.get(TRUNCATED_SIZE); + truncatedSize = (ts == null ? macSize : ts.intValue()); + if (truncatedSize < (macSize / 2)) { + throw new IllegalArgumentException("Truncated size too small"); + } else if (truncatedSize < 10) { + throw new IllegalArgumentException("Truncated size less than 80 bits"); + } + + // we dont use/save the key outside this method + byte[] K = (byte[]) attributes.get(MAC_KEY_MATERIAL); + if (K == null) { // take it as an indication to re-use previous key if set + if (ipadHash == null) + { + throw new InvalidKeyException("Null key"); + } + // we already went through the motions; ie. up to step #4. re-use + underlyingHash = (IMessageDigest) ipadHash.clone(); + return; + } + + if (K.length > blockSize) + { + // (0) replace K with HASH(K) if K is larger than the hash's + // block size. Then pad with zeros until it is the correct + // size (the next `if'). + underlyingHash.update(K, 0, K.length); + K = underlyingHash.digest(); + } + if (K.length < blockSize) + { + // (1) append zeros to the end of K to create a B byte string + // (e.g., if K is of length 20 bytes and B=64, then K will be + // appended with 44 zero bytes 0x00) + int limit = (K.length > blockSize) ? blockSize : K.length; + byte[] newK = new byte[blockSize]; + System.arraycopy(K, 0, newK, 0, limit); + K = newK; + } + + underlyingHash.reset(); + opadHash = (IMessageDigest) underlyingHash.clone(); + if (ipad == null) + { + ipad = new byte[blockSize]; + } + // (2) XOR (bitwise exclusive-OR) the B byte string computed in step + // (1) with ipad + // (3) append the stream of data 'text' to the B byte string resulting + // from step (2) + // (4) apply H to the stream generated in step (3) + for (int i = 0; i < blockSize; i++) + { + ipad[i] = (byte)(K[i] ^ IPAD_BYTE); + } + for (int i = 0; i < blockSize; i++) + { + opadHash.update((byte)(K[i] ^ OPAD_BYTE)); + } + + underlyingHash.update(ipad, 0, blockSize); + ipadHash = (IMessageDigest) underlyingHash.clone(); + K = null; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/TLSRandom.java b/libjava/classpath/gnu/javax/net/ssl/provider/TLSRandom.java new file mode 100644 index 000000000..ded632928 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/TLSRandom.java @@ -0,0 +1,252 @@ +/* TLSRandom.java -- The TLS pseudo-random function. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.security.InvalidKeyException; +import java.util.HashMap; +import java.util.Map; + +import gnu.java.security.hash.HashFactory; +import gnu.javax.crypto.mac.IMac; +import gnu.java.security.prng.IRandom; + +class TLSRandom implements IRandom +{ + + // Fields. + // ------------------------------------------------------------------------- + + /** + * Property name for the secret that will be used to initialize the HMACs. + */ + static final String SECRET = "jessie.tls.prng.secret"; + + /** + * Property name for the seed. + */ + static final String SEED = "jessie.tls.prng.seed"; + + private final IMac hmac_sha, hmac_md5; + private byte[] sha_a, md5_a; + private byte[] seed; + private final byte[] buffer; + private int idx; + private boolean init; + + // Constructors. + // ------------------------------------------------------------------------- + + TLSRandom() + { + hmac_sha = new TLSHMac(HashFactory.getInstance("SHA1")); + hmac_md5 = new TLSHMac(HashFactory.getInstance("MD5")); + buffer = new byte[80]; // 80 == LCM of 16 and 20. + idx = 0; + init = false; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException shouldNotHappen) + { + throw new Error(); + } + } + + public void init(Map attributes) + { + HashMap sha_attr = new HashMap(); + HashMap md5_attr = new HashMap(); + byte[] secret = (byte[]) attributes.get(SECRET); + if (secret != null) + { + int l = (secret.length >>> 1) + (secret.length & 1); + byte[] s1 = Util.trim(secret, 0, l); + byte[] s2 = Util.trim(secret, secret.length - l, l); + md5_attr.put(IMac.MAC_KEY_MATERIAL, s1); + sha_attr.put(IMac.MAC_KEY_MATERIAL, s2); + try + { + hmac_md5.init(md5_attr); + hmac_sha.init(sha_attr); + } + catch (InvalidKeyException ike) + { + throw new Error(ike.toString()); + } + } + else if (!init) + { + throw new IllegalArgumentException("no secret supplied"); + } + // else re-use + + byte[] seeed = (byte[]) attributes.get(SEED); + if (seeed != null) + { + seed = (byte[]) seeed.clone(); + } + else if (!init) + { + throw new IllegalArgumentException("no seed supplied"); + } + // else re-use + + // A(0) is the seed, A(1) = HMAC_hash(secret, A(0)). + hmac_md5.update(seed, 0, seed.length); + md5_a = hmac_md5.digest(); + hmac_md5.reset(); + hmac_sha.update(seed, 0, seed.length); + sha_a = hmac_sha.digest(); + hmac_sha.reset(); + fillBuffer(); + init = true; + } + + public String name() + { + return "TLSRandom"; + } + + public byte nextByte() + { + if (!init) + throw new IllegalStateException(); + if (idx >= buffer.length) + fillBuffer(); + return buffer[idx++]; + } + + public void nextBytes(byte[] buf, int off, int len) + { + if (!init) + throw new IllegalStateException(); + if (buf == null) + throw new NullPointerException(); + if (off < 0 || off > buf.length || off + len > buf.length) + throw new ArrayIndexOutOfBoundsException(); + int count = 0; + if (idx >= buffer.length) + fillBuffer(); + while (count < len) + { + int l = Math.min(buffer.length-idx, len-count); + System.arraycopy(buffer, idx, buf, off+count, l); + idx += l; + count += l; + if (count < len && idx >= buffer.length) + fillBuffer(); + } + } + + // For future versions of GNU Crypto. No-ops. + public void addRandomByte (byte b) + { + } + + public void addRandomBytes(byte[] buffer) { + addRandomBytes(buffer, 0, buffer.length); + } + + public void addRandomBytes (byte[] b, int i, int j) + { + } + + // Own methods. + // ------------------------------------------------------------------------- + + /* + * The PRF is defined as: + * + * PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR + * P_SHA-1(S2, label + seed); + * + * P_hash is defined as: + * + * P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) + + * HMAC_hash(secret, A(2) + seed) + + * HMAC_hash(secret, A(3) + seed) + ... + * + * And A() is defined as: + * + * A(0) = seed + * A(i) = HMAC_hash(secret, A(i-1)) + * + * For simplicity, we compute an 80-byte block on each call, which + * corresponds to five iterations of MD5, and four of SHA-1. + */ + private synchronized void fillBuffer() + { + int len = hmac_md5.macSize(); + for (int i = 0; i < buffer.length; i += len) + { + hmac_md5.update(md5_a, 0, md5_a.length); + hmac_md5.update(seed, 0, seed.length); + byte[] b = hmac_md5.digest(); + hmac_md5.reset(); + System.arraycopy(b, 0, buffer, i, len); + hmac_md5.update(md5_a, 0, md5_a.length); + md5_a = hmac_md5.digest(); + hmac_md5.reset(); + } + len = hmac_sha.macSize(); + for (int i = 0; i < buffer.length; i += len) + { + hmac_sha.update(sha_a, 0, sha_a.length); + hmac_sha.update(seed, 0, seed.length); + byte[] b = hmac_sha.digest(); + hmac_sha.reset(); + for (int j = 0; j < len; j++) + { + buffer[j + i] ^= b[j]; + } + hmac_sha.update(sha_a, 0, sha_a.length); + sha_a = hmac_sha.digest(); + hmac_sha.reset(); + } + idx = 0; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/TruncatedHMAC.java b/libjava/classpath/gnu/javax/net/ssl/provider/TruncatedHMAC.java new file mode 100644 index 000000000..97fff98dc --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/TrustedAuthorities.java b/libjava/classpath/gnu/javax/net/ssl/provider/TrustedAuthorities.java new file mode 100644 index 000000000..72d072739 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/TrustedAuthorities.java @@ -0,0 +1,297 @@ +/* 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.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/libjava/classpath/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java b/libjava/classpath/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java new file mode 100644 index 000000000..94cd091c5 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java @@ -0,0 +1,81 @@ +/* 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.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/libjava/classpath/gnu/javax/net/ssl/provider/Util.java b/libjava/classpath/gnu/javax/net/ssl/provider/Util.java new file mode 100644 index 000000000..a2004b7aa --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Util.java @@ -0,0 +1,495 @@ +/* Util.java -- Miscellaneous utility methods. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import gnu.java.lang.CPStringBuilder; + +import java.io.PrintWriter; +import java.io.StringWriter; + +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.math.BigInteger; + +import java.nio.ByteBuffer; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.Security; + +/** + * A collection of useful class methods. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +public final class Util +{ + + // Constants. + // ------------------------------------------------------------------------- + + static final String HEX = "0123456789abcdef"; + + // Static methods only. + private Util() { } + + // Class methods. + // ------------------------------------------------------------------------- + + public static Object wrapBuffer(ByteBuffer buffer) + { + return wrapBuffer(buffer, ""); + } + + public static Object wrapBuffer(ByteBuffer buffer, String prefix) + { + return new WrappedBuffer(buffer, prefix); + } + + private static class WrappedBuffer + { + private final ByteBuffer buffer; + private final String prefix; + + WrappedBuffer(ByteBuffer buffer, String prefix) + { + this.buffer = buffer; + this.prefix = prefix; + } + + public String toString() + { + return hexDump(buffer, prefix); + } + } + + /** + * Convert a hexadecimal string into its byte representation. + * + * @param hex The hexadecimal string. + * @return The converted bytes. + */ + public static byte[] toByteArray(String hex) + { + hex = hex.toLowerCase(); + byte[] buf = new byte[hex.length() / 2]; + int j = 0; + for (int i = 0; i < buf.length; i++) + { + buf[i] = (byte) ((Character.digit(hex.charAt(j++), 16) << 4) | + Character.digit(hex.charAt(j++), 16)); + } + return buf; + } + + /** + * Convert a byte array to a hexadecimal string, as though it were a + * big-endian arbitrarily-sized integer. + * + * @param buf The bytes to format. + * @param off The offset to start at. + * @param len The number of bytes to format. + * @return A hexadecimal representation of the specified bytes. + */ + public static String toHexString(byte[] buf, int off, int len) + { + CPStringBuilder str = new CPStringBuilder(); + for (int i = 0; i < len; i++) + { + str.append(HEX.charAt(buf[i+off] >>> 4 & 0x0F)); + str.append(HEX.charAt(buf[i+off] & 0x0F)); + } + return str.toString(); + } + + /** + * See {@link #toHexString(byte[],int,int)}. + */ + public static String toHexString(byte[] buf) + { + return Util.toHexString(buf, 0, buf.length); + } + + /** + * Convert a byte array to a hexadecimal string, separating octets + * with the given character. + * + * @param buf The bytes to format. + * @param off The offset to start at. + * @param len The number of bytes to format. + * @param sep The character to insert between octets. + * @return A hexadecimal representation of the specified bytes. + */ + public static String toHexString(byte[] buf, int off, int len, char sep) + { + CPStringBuilder str = new CPStringBuilder(); + for (int i = 0; i < len; i++) + { + str.append(HEX.charAt(buf[i+off] >>> 4 & 0x0F)); + str.append(HEX.charAt(buf[i+off] & 0x0F)); + if (i < len - 1) + str.append(sep); + } + return str.toString(); + } + + /** + * See {@link #toHexString(byte[],int,int,char)}. + */ + public static String toHexString(byte[] buf, char sep) + { + return Util.toHexString(buf, 0, buf.length, sep); + } + + /** + * Create a representation of the given byte array similar to the + * output of `hexdump -C', which is + * + *

    OFFSET  SIXTEEN-BYTES-IN-HEX  PRINTABLE-BYTES
    + * + *

    The printable bytes show up as-is if they are printable and + * not a newline character, otherwise showing as '.'. + * + * @param buf The bytes to format. + * @param off The offset to start at. + * @param len The number of bytes to encode. + * @param prefix A string to prepend to every line. + * @return The formatted string. + */ + public static String hexDump(byte[] buf, int off, int len, String prefix) + { + String nl = getProperty("line.separator"); + CPStringBuilder str = new CPStringBuilder(); + int i = 0; + while (i < len) + { + if (prefix != null) + str.append(prefix); + str.append(Util.formatInt(i+off, 16, 8)); + str.append(" "); + String s = Util.toHexString(buf, i+off, Math.min(16, len-i), ' '); + str.append(s); + for (int j = s.length(); j < 49; j++) + str.append(" "); + for (int j = 0; j < Math.min(16, len - i); j++) + { + if ((buf[i+off+j] & 0xFF) < 0x20 || (buf[i+off+j] & 0xFF) > 0x7E) + str.append('.'); + else + str.append((char) (buf[i+off+j] & 0xFF)); + } + str.append(nl); + i += 16; + } + return str.toString(); + } + + public static String hexDump (ByteBuffer buf) + { + return hexDump (buf, null); + } + + public static String hexDump (ByteBuffer buf, String prefix) + { + buf = buf.duplicate(); + StringWriter str = new StringWriter (); + PrintWriter out = new PrintWriter (str); + int i = 0; + int len = buf.remaining(); + byte[] line = new byte[16]; + while (i < len) + { + if (prefix != null) + out.print(prefix); + out.print(Util.formatInt (i, 16, 8)); + out.print(" "); + int l = Math.min(16, len - i); + buf.get(line, 0, l); + String s = Util.toHexString(line, 0, l, ' '); + out.print(s); + for (int j = s.length(); j < 49; j++) + out.print(' '); + for (int j = 0; j < l; j++) + { + int c = line[j] & 0xFF; + if (c < 0x20 || c > 0x7E) + out.print('.'); + else + out.print((char) c); + } + out.println(); + i += 16; + } + return str.toString(); + } + + /** + * See {@link #hexDump(byte[],int,int,String)}. + */ + public static String hexDump(byte[] buf, int off, int len) + { + return hexDump(buf, off, len, ""); + } + + /** + * See {@link #hexDump(byte[],int,int,String)}. + */ + public static String hexDump(byte[] buf, String prefix) + { + return hexDump(buf, 0, buf.length, prefix); + } + + /** + * See {@link #hexDump(byte[],int,int,String)}. + */ + public static String hexDump(byte[] buf) + { + return hexDump(buf, 0, buf.length); + } + + /** + * Format an integer into the specified radix, zero-filled. + * + * @param i The integer to format. + * @param radix The radix to encode to. + * @param len The target length of the string. The string is + * zero-padded to this length, but may be longer. + * @return The formatted integer. + */ + public static String formatInt(int i, int radix, int len) + { + String s = Integer.toString(i, radix); + CPStringBuilder buf = new CPStringBuilder(); + for (int j = 0; j < len - s.length(); j++) + buf.append("0"); + buf.append(s); + return buf.toString(); + } + + /** + * Concatenate two byte arrays into one. + * + * @param b1 The first byte array. + * @param b2 The second byte array. + * @return The concatenation of b1 and b2. + */ + public static byte[] concat(byte[] b1, byte[] b2) + { + byte[] b3 = new byte[b1.length+b2.length]; + System.arraycopy(b1, 0, b3, 0, b1.length); + System.arraycopy(b2, 0, b3, b1.length, b2.length); + return b3; + } + + /** + * See {@link #trim(byte[],int,int)}. + */ + public static byte[] trim(byte[] buffer, int len) + { + return trim(buffer, 0, len); + } + + /** + * Returns a portion of a byte array, possibly zero-filled. + * + * @param buffer The byte array to trim. + * @param off The offset to begin reading at. + * @param len The number of bytes to return. This value can be larger + * than buffer.length - off, in which case the rest of the + * returned byte array will be filled with zeros. + * @throws IndexOutOfBoundsException If off or len is + * negative, or if off is larger than the byte array's + * length. + * @return The trimmed byte array. + */ + public static byte[] trim(byte[] buffer, int off, int len) + { + if (off < 0 || len < 0 || off > buffer.length) + throw new IndexOutOfBoundsException("max=" + buffer.length + + " off=" + off + " len=" + len); + if (off == 0 && len == buffer.length) + return buffer; + byte[] b = new byte[len]; + System.arraycopy(buffer, off, b, 0, Math.min(len, buffer.length - off)); + return b; + } + + /** + * Returns the byte array representation of the given big integer with + * the leading zero byte (if any) trimmed off. + * + * @param bi The integer to trim. + * @return The byte representation of the big integer, with any leading + * zero removed. + */ + public static byte[] trim(BigInteger bi) + { + byte[] buf = bi.toByteArray(); + if (buf[0] == 0x00 && !bi.equals(BigInteger.ZERO)) + { + return trim(buf, 1, buf.length - 1); + } + else + { + return buf; + } + } + + /** + * Returns the integer value of {@link + * java.lang.System#currentTimeMillis()} / 1000. + * + * @return The current time, in seconds. + */ + public static int unixTime() + { + return (int) (System.currentTimeMillis() / 1000L); + } + + /** + * Transform an Object array into another by calling the given method + * on each object. The returned object array will have the runtime + * type of returnType. For example, the following will transform + * array of objects into their String representations, returning a String + * array. For example: + * + *

    + * String[] strings = (String[]) Util.transform(array, String.class, + * "toString", null); + *

    + * + *

    If any element of the given array is null, then that + * entry in the returned array will also be null. + * + * @param array The array to transform. It does not need to be of + * uniform type. + * @param returnType The desired return type of the returned array. + * This must by the component type, not the array type. + * @param method The name of the method to invoke from each object. + * @param args The arguments to pass to the method, or null + * if the method takes no arguments. + * @throws InvocationTargetException If an exception occurs while + * calling method of any object. + * @throws NoSuchMethodException If method is not the name of + * a valid method of any component of the array. + * @throws ClassCastException If the returned object from the method + * is not assignable to the return type. + * @throws IllegalArgumentException If args is not appropriate + * for method + * @throws IllegalAccessException If method is not accessible. + * @throws SecurityException If method is not accessible. + * @return An array containing the output of method called on + * each element of array with args. The return type + * of the array will be an array of returnType. + */ + static Object[] transform(Object[] array, Class returnType, + String method, Object[] args) + throws InvocationTargetException, NoSuchMethodException, + IllegalAccessException + { + if (args == null) + args = new Object[0]; + Object[] result = (Object[]) Array.newInstance(returnType, array.length); + Class[] argsClasses = new Class[args.length]; + for (int i = 0; i < args.length; i++) + { + argsClasses[i] = args[i].getClass(); + } + for (int i = 0; i < array.length; i++) + { + if (array[i] == null) + { + result[i] = null; + continue; + } + Class objClass = array[i].getClass(); + Method objMethod = objClass.getMethod(method, argsClasses); + Object o = objMethod.invoke(array[i], args); + if (!returnType.isAssignableFrom(o.getClass())) + throw new ClassCastException(); + result[i] = o; + } + return result; + } + + /** + * Get a system property as a privileged action. + * + * @param name The name of the property to get. + * @return The property named name, or null if the property is + * not set. + * @throws SecurityException If the Jessie code still does not have + * permission to read the property. + */ + @Deprecated static String getProperty(final String name) + { + return (String) AccessController.doPrivileged( + new PrivilegedAction() + { + public Object run() + { + return System.getProperty(name); + } + } + ); + } + + /** + * Get a security property as a privileged action. + * + * @param name The name of the property to get. + * @return The property named name, or null if the property is + * not set. + * @throws SecurityException If the Jessie code still does not have + * permission to read the property. + */ + @Deprecated static String getSecurityProperty(final String name) + { + return (String) AccessController.doPrivileged( + new PrivilegedAction() + { + public Object run() + { + return Security.getProperty(name); + } + } + ); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/X500PrincipalList.java b/libjava/classpath/gnu/javax/net/ssl/provider/X500PrincipalList.java new file mode 100644 index 000000000..ffdcbbad2 --- /dev/null +++ b/libjava/classpath/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 (); + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java b/libjava/classpath/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java new file mode 100644 index 000000000..a63cb2cbe --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java @@ -0,0 +1,396 @@ +/* X509KeyManagerFactory.java -- X.509 key manager factory. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.FileInputStream; +import java.io.IOException; +import java.net.Socket; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Enumeration; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.Principal; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.DSAPublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +import java.util.Collections; +import java.util.Map; +import java.util.List; + +import javax.crypto.interfaces.DHPrivateKey; +import javax.crypto.interfaces.DHPublicKey; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactorySpi; +import javax.net.ssl.ManagerFactoryParameters; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.X509ExtendedKeyManager; +import gnu.javax.net.ssl.NullManagerParameters; +import gnu.javax.net.ssl.PrivateCredentials; + +/** + * This class implements a {@link javax.net.ssl.KeyManagerFactory} engine + * for the ``JessieX509'' algorithm. + */ +public class X509KeyManagerFactory extends KeyManagerFactorySpi +{ + + // Fields. + // ------------------------------------------------------------------------- + + private Manager current; + + // Constructor. + // ------------------------------------------------------------------------- + + public X509KeyManagerFactory() + { + super(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + protected KeyManager[] engineGetKeyManagers() + { + if (current == null) + { + throw new IllegalStateException(); + } + return new KeyManager[] { current }; + } + + protected void engineInit(ManagerFactoryParameters params) + throws InvalidAlgorithmParameterException + { + if (params instanceof NullManagerParameters) + { + current = new Manager(Collections.EMPTY_MAP, Collections.EMPTY_MAP); + } + else if (params instanceof PrivateCredentials) + { + List 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(); + while (c.hasNext() && k.hasNext()) + { + certMap.put(String.valueOf(i), c.next()); + keyMap.put(String.valueOf(i), k.next()); + i++; + } + current = new Manager(keyMap, certMap); + } + else + { + throw new InvalidAlgorithmParameterException(); + } + } + + protected void engineInit(KeyStore store, char[] passwd) + throws KeyStoreException, NoSuchAlgorithmException, + UnrecoverableKeyException + { + if (store == null) + { + String s = Util.getProperty("javax.net.ssl.keyStoreType"); + if (s == null) + s = KeyStore.getDefaultType(); + store = KeyStore.getInstance(s); + s = Util.getProperty("javax.net.ssl.keyStore"); + if (s == null) + return; + String p = Util.getProperty("javax.net.ssl.keyStorePassword"); + try + { + store.load(new FileInputStream(s), p != null ? p.toCharArray() : null); + } + catch (IOException ioe) + { + throw new KeyStoreException(ioe.toString()); + } + catch (CertificateException ce) + { + throw new KeyStoreException(ce.toString()); + } + } + + HashMap p = new HashMap(); + HashMap c + = new HashMap(); + Enumeration aliases = store.aliases(); + UnrecoverableKeyException exception = null; + while (aliases.hasMoreElements()) + { + String alias = (String) aliases.nextElement(); + if (!store.isKeyEntry(alias)) + { + continue; + } + X509Certificate[] chain = null; + Certificate[] chain2 = store.getCertificateChain (alias); + if (chain2 != null && chain2.length > 0 && + (chain2[0] instanceof X509Certificate)) + { + chain = toX509Chain(chain2); + } + else + { + continue; + } + PrivateKey key = null; + try + { + key = (PrivateKey) store.getKey(alias, passwd); + } + catch (UnrecoverableKeyException uke) + { + exception = uke; + continue; + } + if (key == null) + { + continue; + } + p.put(alias, key); + c.put(alias, chain); + } + if (p.isEmpty () && c.isEmpty ()) + { + if (exception != null) + { + throw exception; + } + throw new KeyStoreException ("no private credentials found"); + } + current = this.new Manager(p, c); + } + + private static X509Certificate[] toX509Chain(Certificate[] chain) + { + if (chain instanceof X509Certificate[]) + { + return (X509Certificate[]) chain; + } + X509Certificate[] _chain = new X509Certificate[chain.length]; + for (int i = 0; i < chain.length; i++) + _chain[i] = (X509Certificate) chain[i]; + return _chain; + } + + // Inner class. + // ------------------------------------------------------------------------- + + private class Manager extends X509ExtendedKeyManager + { + // Fields. + // ----------------------------------------------------------------------- + + private final Map privateKeys; + private final Map certChains; + + // Constructor. + // ----------------------------------------------------------------------- + + Manager(Map privateKeys, + Map certChains) + { + this.privateKeys = privateKeys; + this.certChains = certChains; + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public String chooseClientAlias(String[] keyTypes, Principal[] issuers, + Socket socket) + { + for (int i = 0; i < keyTypes.length; i++) + { + String[] s = getClientAliases(keyTypes[i], issuers); + if (s.length > 0) + return s[0]; + } + return null; + } + + public @Override String chooseEngineClientAlias(String[] keyTypes, + Principal[] issuers, + SSLEngine engine) + { + for (String type : keyTypes) + { + String[] s = getClientAliases(type, issuers); + if (s.length > 0) + return s[0]; + } + return null; + } + + public String[] getClientAliases(String keyType, Principal[] issuers) + { + return getAliases(keyType, issuers); + } + + public String chooseServerAlias(String keyType, Principal[] issuers, + Socket socket) + { + String[] s = getServerAliases(keyType, issuers); + if (s.length > 0) + return s[0]; + return null; + } + + public @Override String chooseEngineServerAlias(String keyType, + Principal[] issuers, + SSLEngine engine) + { + String[] s = getServerAliases(keyType, issuers); + if (s.length > 0) + return s[0]; + return null; + } + + public String[] getServerAliases(String keyType, Principal[] issuers) + { + return getAliases(keyType, issuers); + } + + private String[] getAliases(String keyType, Principal[] issuers) + { + LinkedList l = new LinkedList(); + for (Iterator i = privateKeys.keySet().iterator(); i.hasNext(); ) + { + String alias = (String) i.next(); + X509Certificate[] chain = getCertificateChain(alias); + if (chain.length == 0) + continue; + PrivateKey privKey = getPrivateKey(alias); + if (privKey == null) + continue; + PublicKey pubKey = chain[0].getPublicKey(); + if (keyType.equalsIgnoreCase("RSA") + || keyType.equalsIgnoreCase("DHE_RSA") + || keyType.equalsIgnoreCase("SRP_RSA") + || keyType.equalsIgnoreCase("rsa_sign") + || keyType.equalsIgnoreCase("RSA_PSK")) + { + if (!(privKey instanceof RSAPrivateKey) || + !(pubKey instanceof RSAPublicKey)) + continue; + } + else if (keyType.equalsIgnoreCase("DHE_DSS") + || keyType.equalsIgnoreCase("dss_sign") + || keyType.equalsIgnoreCase("SRP_DSS") + || keyType.equalsIgnoreCase("DSA")) + { + if (!(privKey instanceof DSAPrivateKey) || + !(pubKey instanceof DSAPublicKey)) + continue; + } + else if (keyType.equalsIgnoreCase("DH_RSA") + || keyType.equalsIgnoreCase("rsa_fixed_dh")) + { + if (!(privKey instanceof DHPrivateKey) || + !(pubKey instanceof DHPublicKey)) + continue; + if (!chain[0].getSigAlgName().equalsIgnoreCase("RSA")) + continue; + } + else if (keyType.equalsIgnoreCase("DH_DSS") + || keyType.equalsIgnoreCase("dss_fixed_dh")) + { + if (!(privKey instanceof DHPrivateKey) || + !(pubKey instanceof DHPublicKey)) + continue; + if (!chain[0].getSigAlgName().equalsIgnoreCase("DSA")) + continue; + } + else // Unknown key type; ignore it. + continue; + if (issuers == null || issuers.length == 0) + { + l.add(alias); + continue; + } + for (Principal issuer : issuers) + { + if (chain[0].getIssuerDN().equals(issuer)) + { + l.add(alias); + break; + } + } + } + return l.toArray(new String[l.size()]); + } + + public X509Certificate[] getCertificateChain(String alias) + { + X509Certificate[] c = (X509Certificate[]) certChains.get(alias); + return c != null ? (X509Certificate[]) c.clone() : null; + } + + public PrivateKey getPrivateKey(String alias) + { + return (PrivateKey) privateKeys.get(alias); + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java b/libjava/classpath/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java new file mode 100644 index 000000000..ddd2f9c8b --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java @@ -0,0 +1,295 @@ +/* X509TrustManagerFactory.java -- X.509 trust manager factory. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.FileInputStream; +import java.io.IOException; + +import java.util.Arrays; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Set; + +import java.security.AccessController; +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertPath; +import java.security.cert.CertPathValidator; +import java.security.cert.CertPathValidatorException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.PKIXParameters; +import java.security.cert.TrustAnchor; +import java.security.cert.X509Certificate; + +import javax.net.ssl.ManagerFactoryParameters; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactorySpi; +import javax.net.ssl.X509TrustManager; + +import gnu.java.security.action.GetPropertyAction; +import gnu.java.security.x509.X509CertPath; +import gnu.javax.net.ssl.NullManagerParameters; +import gnu.javax.net.ssl.StaticTrustAnchors; + +/** + * This class implements a {@link javax.net.ssl.TrustManagerFactory} engine + * for the ``JessieX509'' algorithm. + */ +public class X509TrustManagerFactory extends TrustManagerFactorySpi +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + private static final String sep + = AccessController.doPrivileged(new GetPropertyAction("file.separator")); + + /** + * The location of the JSSE key store. + */ + private static final String JSSE_CERTS + = AccessController.doPrivileged(new GetPropertyAction("java.home")) + + sep + "lib" + sep + "security" + sep + "jssecerts"; + + /** + * The location of the system key store, containing the CA certs. + */ + private static final String CA_CERTS + = AccessController.doPrivileged(new GetPropertyAction("java.home")) + + sep + "lib" + sep + "security" + sep + "cacerts"; + + private Manager current; + + // Construtors. + // ------------------------------------------------------------------------- + + public X509TrustManagerFactory() + { + super(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + protected TrustManager[] engineGetTrustManagers() + { + if (current == null) + { + throw new IllegalStateException("not initialized"); + } + return new TrustManager[] { current }; + } + + protected void engineInit(ManagerFactoryParameters params) + throws InvalidAlgorithmParameterException + { + if (params instanceof StaticTrustAnchors) + { + current = new Manager(((StaticTrustAnchors) params).getCertificates()); + } + else if (params instanceof NullManagerParameters) + { + current = new Manager(new X509Certificate[0]); + } + else + { + throw new InvalidAlgorithmParameterException(); + } + } + + protected void engineInit(KeyStore store) throws KeyStoreException + { + if (store == null) + { + GetPropertyAction gpa = new GetPropertyAction("javax.net.ssl.trustStoreType"); + String s = AccessController.doPrivileged(gpa); + if (s == null) + s = KeyStore.getDefaultType(); + store = KeyStore.getInstance(s); + try + { + s = AccessController.doPrivileged(gpa.setParameters("javax.net.ssl.trustStore")); + FileInputStream in = null; + if (s == null) + { + try + { + in = new FileInputStream(JSSE_CERTS); + } + catch (IOException e) + { + in = new FileInputStream(CA_CERTS); + } + } + else + { + in = new FileInputStream(s); + } + String p = AccessController.doPrivileged(gpa.setParameters("javax.net.ssl.trustStorePassword")); + store.load(in, p != null ? p.toCharArray() : null); + } + catch (IOException ioe) + { + throw new KeyStoreException(ioe); + } + catch (CertificateException ce) + { + throw new KeyStoreException(ce); + } + catch (NoSuchAlgorithmException nsae) + { + throw new KeyStoreException(nsae); + } + } + + LinkedList l = new LinkedList(); + Enumeration aliases = store.aliases(); + while (aliases.hasMoreElements()) + { + String alias = (String) aliases.nextElement(); + if (!store.isCertificateEntry(alias)) + continue; + Certificate c = store.getCertificate(alias); + if (!(c instanceof X509Certificate)) + continue; + l.add((X509Certificate) c); + } + current = this.new Manager(l.toArray(new X509Certificate[l.size()])); + } + + // Inner class. + // ------------------------------------------------------------------------- + + /** + * The actual manager implementation returned. + */ + private class Manager implements X509TrustManager + { + + // Fields. + // ----------------------------------------------------------------------- + + private final Set anchors; + + // Constructor. + // ----------------------------------------------------------------------- + + Manager(X509Certificate[] trusted) + { + anchors = new HashSet(); + if (trusted != null) + { + for (X509Certificate cert : trusted) + { + anchors.add(new TrustAnchor(cert, null)); + } + } + } + + // Instance methodns. + // ----------------------------------------------------------------------- + + public void checkClientTrusted(X509Certificate[] chain, String authType) + throws CertificateException + { + checkTrusted(chain, authType); + } + + public void checkServerTrusted(X509Certificate[] chain, String authType) + throws CertificateException + { + checkTrusted(chain, authType); + } + + public X509Certificate[] getAcceptedIssuers() + { + return anchors.toArray(new X509Certificate[anchors.size()]); + } + + // Own methods. + // ----------------------------------------------------------------------- + + private void checkTrusted(X509Certificate[] chain, String authType) + throws CertificateException + { + CertPathValidator validator = null; + + try + { + validator = CertPathValidator.getInstance("PKIX"); + } + catch (NoSuchAlgorithmException nsae) + { + throw new CertificateException(nsae); + } + + CertPath path = new X509CertPath(Arrays.asList(chain)); + + PKIXParameters params = null; + try + { + params = new PKIXParameters(anchors); + // XXX we probably do want to enable revocation, but it's a pain + // in the ass. + params.setRevocationEnabled(false); + } + catch (InvalidAlgorithmParameterException iape) + { + throw new CertificateException(iape); + } + + try + { + validator.validate(path, params); + } + catch (CertPathValidatorException cpve) + { + throw new CertificateException(cpve); + } + catch (InvalidAlgorithmParameterException iape) + { + throw new CertificateException(iape); + } + } + } +} diff --git a/libjava/classpath/gnu/javax/print/CupsIppOperation.java b/libjava/classpath/gnu/javax/print/CupsIppOperation.java new file mode 100644 index 000000000..96744c1f3 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/CupsIppOperation.java @@ -0,0 +1,99 @@ +/* CupsIppOperation.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print; + + +/** + * Operations as provided by CUPS up to version 1.1 + *

    + * See: CUPS Implementation of IPP, chapter 3.2
    + * http://www.cups.org/doc-1.1/ipp.html + *

    + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class CupsIppOperation +{ + + /** Get the default destination - since CUPS 1.0 */ + public static final int CUPS_GET_DEFAULT = 0x4001; + + /** Get all of the available printers - since CUPS 1.0 */ + public static final int CUPS_GET_PRINTERS = 0x4002; + + /** Add or modify a printer - since CUPS 1.0 */ + public static final int CUPS_ADD_MODIFY_PRINTER = 0x4003; + + /** Delete a printer - since CUPS 1.0 */ + public static final int CUPS_DELETE_PRINTER = 0x4004; + + /** Get all of the available printer classes - since CUPS 1.0 */ + public static final int CUPS_GET_CLASSES = 0x4005; + + /** Add or modify a printer class - since CUPS 1.0 */ + public static final int CUPS_ADD_MODIFY_CLASS = 0x4006; + + /** Delete a printer class - since CUPS 1.0 */ + public static final int CUPS_DELETE_CLASS = 0x4007; + + /** Accept jobs on a printer or printer class - since CUPS 1.0 */ + public static final int CUPS_ACCEPT_JOBS = 0x4008; + + /** Reject jobs on a printer or printer class - since CUPS 1.0 */ + public static final int CUPS_REJECT_JOBS = 0x4009; + + /** Set the default destination - since CUPS 1.0 */ + public static final int CUPS_SET_DEFAULT = 0x400A; + + /** Get all of the available PPDs - since CUPS 1.1 */ + public static final int CUPS_GET_DEVICES = 0x400B; + + /** Get all of the available PPDs - since CUPS 1.1 */ + public static final int CUPS_GET_PPDS = 0x400C; + + /** Move a job to a different printer - since CUPS 1.1 */ + public static final int CUPS_MOVE_JOB = 0x400D; + + + private CupsIppOperation() + { + // not to be instantiated + } + +} diff --git a/libjava/classpath/gnu/javax/print/CupsMediaMapping.java b/libjava/classpath/gnu/javax/print/CupsMediaMapping.java new file mode 100644 index 000000000..49bd94d6f --- /dev/null +++ b/libjava/classpath/gnu/javax/print/CupsMediaMapping.java @@ -0,0 +1,176 @@ +/* CupsMediaMapping.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import javax.print.attribute.standard.MediaSizeName; + +/** + * Provides the currently known mappings of the media attribute + * values of the CUPS printing system to the IPP standard values. + *

    + * The mapping is used to build up print service specific mappings + * for use of media attribute translation between Java JPS API and + * CUPS. + *

    + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public class CupsMediaMapping +{ + // the mapping map + private static final HashMap ippByCups = new HashMap(); + + /** + * Initialize currently known mappings. + */ + static + { + ippByCups.put("Postcard", MediaSizeName.JAPANESE_POSTCARD); + ippByCups.put("Statement", MediaSizeName.INVOICE); + + ippByCups.put("Letter", MediaSizeName.NA_LETTER); + ippByCups.put("Executive", MediaSizeName.EXECUTIVE); + ippByCups.put("Legal", MediaSizeName.NA_LEGAL); + + ippByCups.put("A0", MediaSizeName.ISO_A0); + ippByCups.put("A1", MediaSizeName.ISO_A1); + ippByCups.put("A2", MediaSizeName.ISO_A2); + ippByCups.put("A3", MediaSizeName.ISO_A3); + ippByCups.put("A4", MediaSizeName.ISO_A4); + ippByCups.put("A5", MediaSizeName.ISO_A5); + ippByCups.put("A6", MediaSizeName.ISO_A6); + ippByCups.put("A7", MediaSizeName.ISO_A7); + ippByCups.put("A8", MediaSizeName.ISO_A8); + ippByCups.put("A9", MediaSizeName.ISO_A9); + ippByCups.put("A10", MediaSizeName.ISO_A10); + + ippByCups.put("B0", MediaSizeName.JIS_B0); + ippByCups.put("B1", MediaSizeName.JIS_B1); + ippByCups.put("B2", MediaSizeName.JIS_B2); + ippByCups.put("B3", MediaSizeName.JIS_B3); + ippByCups.put("B4", MediaSizeName.JIS_B4); + ippByCups.put("B5", MediaSizeName.JIS_B5); + ippByCups.put("B6", MediaSizeName.JIS_B6); + ippByCups.put("B7", MediaSizeName.JIS_B7); + ippByCups.put("B8", MediaSizeName.JIS_B8); + ippByCups.put("B9", MediaSizeName.JIS_B9); + ippByCups.put("B10", MediaSizeName.JIS_B10); + + ippByCups.put("ISOB0", MediaSizeName.ISO_B0); + ippByCups.put("ISOB1", MediaSizeName.ISO_B1); + ippByCups.put("ISOB2", MediaSizeName.ISO_B2); + ippByCups.put("ISOB3", MediaSizeName.ISO_B3); + ippByCups.put("ISOB4", MediaSizeName.ISO_B4); + ippByCups.put("ISOB5", MediaSizeName.ISO_B5); + ippByCups.put("ISOB6", MediaSizeName.ISO_B6); + ippByCups.put("ISOB7", MediaSizeName.ISO_B7); + ippByCups.put("ISOB8", MediaSizeName.ISO_B8); + ippByCups.put("ISOB9", MediaSizeName.ISO_B9); + ippByCups.put("ISOB10", MediaSizeName.ISO_B10); + ippByCups.put("EnvISOB0", MediaSizeName.ISO_B0); + ippByCups.put("EnvISOB1", MediaSizeName.ISO_B1); + ippByCups.put("EnvISOB2", MediaSizeName.ISO_B2); + ippByCups.put("EnvISOB3", MediaSizeName.ISO_B3); + ippByCups.put("EnvISOB4", MediaSizeName.ISO_B4); + ippByCups.put("EnvISOB5", MediaSizeName.ISO_B5); + ippByCups.put("EnvISOB6", MediaSizeName.ISO_B6); + ippByCups.put("EnvISOB7", MediaSizeName.ISO_B7); + ippByCups.put("EnvISOB8", MediaSizeName.ISO_B8); + ippByCups.put("EnvISOB9", MediaSizeName.ISO_B9); + ippByCups.put("EnvISOB10", MediaSizeName.ISO_B10); + + ippByCups.put("C0", MediaSizeName.ISO_C0); + ippByCups.put("C1", MediaSizeName.ISO_C1); + ippByCups.put("C2", MediaSizeName.ISO_C2); + ippByCups.put("C3", MediaSizeName.ISO_C3); + ippByCups.put("C4", MediaSizeName.ISO_C4); + ippByCups.put("C5", MediaSizeName.ISO_C5); + ippByCups.put("C6", MediaSizeName.ISO_C6); + + ippByCups.put("EnvPersonal", MediaSizeName.PERSONAL_ENVELOPE); + ippByCups.put("EnvMonarch", MediaSizeName.MONARCH_ENVELOPE); + ippByCups.put("Monarch", MediaSizeName.MONARCH_ENVELOPE); + ippByCups.put("Env9", MediaSizeName.NA_NUMBER_9_ENVELOPE); + ippByCups.put("Env10", MediaSizeName.NA_NUMBER_10_ENVELOPE); + ippByCups.put("Env11", MediaSizeName.NA_NUMBER_11_ENVELOPE); + ippByCups.put("Env12", MediaSizeName.NA_NUMBER_12_ENVELOPE); + ippByCups.put("Env14", MediaSizeName.NA_NUMBER_14_ENVELOPE); + ippByCups.put("c8x10", MediaSizeName.NA_8X10); + + ippByCups.put("EnvDL", MediaSizeName.ISO_DESIGNATED_LONG); + ippByCups.put("DL", MediaSizeName.ISO_DESIGNATED_LONG); + ippByCups.put("EnvC0", MediaSizeName.ISO_C0); + ippByCups.put("EnvC1", MediaSizeName.ISO_C1); + ippByCups.put("EnvC2", MediaSizeName.ISO_C2); + ippByCups.put("EnvC3", MediaSizeName.ISO_C3); + ippByCups.put("EnvC4", MediaSizeName.ISO_C4); + ippByCups.put("EnvC5", MediaSizeName.ISO_C5); + ippByCups.put("EnvC6", MediaSizeName.ISO_C6); + } + + /** + * Returns the IPP media name of the given cups name. + * + * @param cupsName the name in cups + * @return The IPP name if a mapping is known, null otherwise. + */ + public static final String getIppName(String cupsName) + { + return (String) ippByCups.get(cupsName); + } + + /** + * Returns the mapping map for iteration. + * + * @return The mapping map as unmodifiable map. + */ + public static final Map getMappingMap() + { + return Collections.unmodifiableMap(ippByCups); + } + + private CupsMediaMapping() + { + // not to be instantiated + } +} diff --git a/libjava/classpath/gnu/javax/print/CupsPrintService.java b/libjava/classpath/gnu/javax/print/CupsPrintService.java new file mode 100644 index 000000000..f3bec996c --- /dev/null +++ b/libjava/classpath/gnu/javax/print/CupsPrintService.java @@ -0,0 +1,104 @@ +/* CupsPrintService.java -- Cups specific implementation subclass + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print; + +import gnu.javax.print.ipp.IppException; +import gnu.javax.print.ipp.IppMultiDocPrintService; +import gnu.javax.print.ipp.IppResponse; + +import java.net.URI; + +import javax.print.DocFlavor; +import javax.print.attribute.AttributeSet; + +/** + * Implementation of the PrintService/MultiDocPrintService + * interface for Cups printers (supports Cups 1.1 and up) + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class CupsPrintService extends IppMultiDocPrintService +{ + + /** + * Creates a CupsPrintService object. + * + * @param uri the URI of the IPP printer. + * @param username the user of this print service. + * @param password the password of the user. + * + * @throws IppException if an error during connection occurs. + */ + public CupsPrintService(URI uri, String username, String password) + throws IppException + { + super(uri, username, password); + } + + /** + * Overridden for CUPS specific handling of the media attribute. + */ + protected Object handleSupportedAttributeValuesResponse(IppResponse response, + Class category) + { + // TODO Implement different behaviour of cups here - actually the Media + // printing attribute stuff. For now just use IPP reference implementation. + return super.handleSupportedAttributeValuesResponse(response, category); + } + + /** + * Overridden for CUPS specific handling of the media attribute. + */ + public Object getDefaultAttributeValue(Class category) + { + // TODO Implement media attribute behaviour for cups here + //if (category.equals(Media.class) + + return super.getDefaultAttributeValue(category); + } + + /** + * Overridden as CUPS does not implement Validate-Job correctly. + */ + public AttributeSet getUnsupportedAttributes(DocFlavor flavor, AttributeSet attributes) + { + // TODO Implement a heuristic unsupported attribute identification. + return super.getUnsupportedAttributes(flavor, attributes); + } +} diff --git a/libjava/classpath/gnu/javax/print/CupsPrintServiceLookup.java b/libjava/classpath/gnu/javax/print/CupsPrintServiceLookup.java new file mode 100644 index 000000000..d537c398f --- /dev/null +++ b/libjava/classpath/gnu/javax/print/CupsPrintServiceLookup.java @@ -0,0 +1,260 @@ +/* CupsPrintServiceLookup.java -- Implementation based on CUPS + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print; + +import gnu.javax.print.ipp.IppException; + +import java.util.ArrayList; + +import javax.print.DocFlavor; +import javax.print.MultiDocPrintService; +import javax.print.PrintService; +import javax.print.PrintServiceLookup; +import javax.print.attribute.Attribute; +import javax.print.attribute.AttributeSet; + +/** + * The platform default implementation based on CUPS. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public class CupsPrintServiceLookup extends PrintServiceLookup +{ + private CupsServer server; + + /** + * Default constructor checking security access. + */ + public CupsPrintServiceLookup() + { + // security + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPrintJobAccess(); + + // use the localhost cups server + server = new CupsServer(null, null); + } + + /** + * This is the printer marked as default in CUPS. + * + * @return The default lookup service or + * null if there is no default. + */ + public PrintService getDefaultPrintService() + { + try + { + return server.getDefaultPrinter(); + } + catch (IppException e) + { + // if discovery fails treat as if there is none + return null; + } + } + + /** + * All printers and printer classes of the CUPS server are checked. + * If flavors or attributes are null the constraint is not used. + * + * @param flavors the document flavors which have to be supported. + * @param attributes the attributes which have to be supported. + * + * @return The multidoc print services of the implementing lookup service + * for the given parameters, or an array of length 0 if none is available. + */ + public MultiDocPrintService[] getMultiDocPrintServices(DocFlavor[] flavors, + AttributeSet attributes) + { + ArrayList result = new ArrayList(); + PrintService[] services = getPrintServices(); + + for (int i=0; i < services.length; i++) + { + if (checkMultiDocPrintService(flavors, attributes, services[i])) + result.add(services[i]); + } + + return (MultiDocPrintService[]) result.toArray( + new MultiDocPrintService[result.size()]); + } + + /** + * These are all printers and printer classes of the CUPS server. + * + * @return All known print services regardless of supported features, + * or an array of length 0 if none is available. + */ + public PrintService[] getPrintServices() + { + ArrayList result = new ArrayList(); + + try + { + result.addAll(server.getAllPrinters()); + result.addAll(server.getAllClasses()); + } + catch (IppException e) + { + // ignore as this method cannot throw exceptions + // if print service discovery fails - bad luck + } + return (PrintService[]) result.toArray(new PrintService[result.size()]); + } + + + /** + * All printers and printer classes of the CUPS server are checked. + * If flavor or attributes are null the constraint is not used. + * + * @param flavor the document flavor which has to be supported. + * @param attributes the attributes which have to be supported. + * + * @return The print services of the implementing lookup service + * for the given parameters, or an array of length 0 if none is available. + */ + public PrintService[] getPrintServices(DocFlavor flavor, + AttributeSet attributes) + { + ArrayList result = new ArrayList(); + PrintService[] services = getPrintServices(); + + for (int i=0; i < services.length; i++) + { + if (checkPrintService(flavor, attributes, services[i])) + result.add(services[i]); + } + + return (PrintService[]) result.toArray(new PrintService[result.size()]); + } + + /** + * Checks the given print service - own method so it can be used also + * to check application registered print services from PrintServiceLookup. + * + * @param flavor the document flavor which has to be supported. + * @param attributes the attributes which have to be supported. + * @param service the service to check + * + * @return true if all constraints match, false + * otherwise. + */ + public boolean checkPrintService(DocFlavor flavor, AttributeSet attributes, + PrintService service) + { + boolean allAttributesSupported = true; + if (flavor == null || service.isDocFlavorSupported(flavor)) + { + if (attributes == null || attributes.size() == 0) + return allAttributesSupported; + + Attribute[] atts = attributes.toArray(); + for (int i = 0; i < atts.length; i++) + { + if (! service.isAttributeCategorySupported(atts[i].getCategory())) + { + allAttributesSupported = false; + break; + } + } + return allAttributesSupported; + } + + return false; + } + + /** + * Checks the given print service - own method so it can be used also + * to check application registered print services from PrintServiceLookup. + * + * @param flavors the document flavors which have to be supported. + * @param attributes the attributes which have to be supported. + * @param service the service to check + * + * @return true if all constraints match, false + * otherwise. + */ + public boolean checkMultiDocPrintService(DocFlavor[] flavors, + AttributeSet attributes, PrintService service) + { + if (service instanceof MultiDocPrintService) + { + boolean allFlavorsSupported = true; + boolean allAttributesSupported = true; + + if (flavors == null || flavors.length != 0) + allFlavorsSupported = true; + else + { + for (int k = 0; k < flavors.length; k++) + { + if (! service.isDocFlavorSupported(flavors[k])) + { + allFlavorsSupported = false; + break; + } + } + } + + if (attributes == null || attributes.size() == 0) + allAttributesSupported = true; + else + { + Attribute[] atts = attributes.toArray(); + for (int j = 0; j < atts.length; j++) + { + if (! service.isAttributeCategorySupported( + atts[j].getCategory())) + { + allAttributesSupported = false; + break; + } + } + } + + if (allAttributesSupported && allFlavorsSupported) + return true; + } + + return false; + } + +} diff --git a/libjava/classpath/gnu/javax/print/CupsServer.java b/libjava/classpath/gnu/javax/print/CupsServer.java new file mode 100644 index 000000000..6dbcfc732 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/CupsServer.java @@ -0,0 +1,288 @@ +/* CupsServer.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print; + +import gnu.javax.print.ipp.IppException; +import gnu.javax.print.ipp.IppPrintService; +import gnu.javax.print.ipp.IppRequest; +import gnu.javax.print.ipp.IppResponse; +import gnu.javax.print.ipp.attribute.RequestedAttributes; +import gnu.javax.print.ipp.attribute.supported.PrinterUriSupported; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * CupsServer represents a host running a cups + * compatible server. It mainly consists of its URI and optional + * user and password combination if access is restricted. + *

    + * It provides methods for retrival of valid CUPS printer uris + * that are used to construct IppPrintService objects. + *

    + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public class CupsServer +{ + /** + * The URI of the CUPS server. + * This is something like: http://localhost:631 + */ + private transient URI uri; + + /** + * The optional username. + */ + private transient String username; + + /** + * The optional password for the user. + */ + private transient String password; + + /** + * Creates a CupsServer object which + * tries to connect to a cups server. + * + * If gnu.javax.print.server is explicitly set, then + * that hostname will be used. Otherwise it will default to localhost. + * + * @param username the username + * @param password the password for the username. + */ + public CupsServer(String username, String password) + { + this.username = username; + this.password = password; + + this.uri = null; + try + { + String serv = System.getProperty("gnu.javax.print.server"); + if( serv != null ) + this.uri = new URI("http://"+serv+":631"); + } + catch(URISyntaxException use) + { + throw new RuntimeException("gnu.javax.print.CupsServer value is not a valid hostname."); + } + catch(SecurityException se) + { + } + + try + { + if( this.uri == null ) + this.uri = new URI("http://localhost:631"); + } + catch (URISyntaxException e) + { + // does not happen + } + } + + /** + * Creates a CupsServer object which + * tries to connect to a running cups server on the + * given URI. + * + * @param uri the URI of the server. + * @param username the username + * @param password the password for the username. + */ + public CupsServer(URI uri, String username, String password) + { + this.uri = uri; + this.username = username; + this.password = password; + } + + /** + * Requests the default printer from this CUPS server. + * This is always returned as IppPrintService. + * + * @return The default printer. + * @throws IppException if problems during request/response processing occur. + */ + public IppPrintService getDefaultPrinter() throws IppException + { + IppResponse response = null; + + try + { + IppRequest request = new IppRequest(uri, username, password); + request.setOperationID((short)CupsIppOperation.CUPS_GET_DEFAULT); + request.setOperationAttributeDefaults(); + + RequestedAttributes requestedAttrs + = new RequestedAttributes("printer-uri-supported"); + request.addOperationAttribute(requestedAttrs); + + response = request.send(); + } + catch (IOException e) + { + throw new IppException("IOException in IPP request/response.", e); + } + + Map printerAttributes = (Map) response.getPrinterAttributes().get(0); + Set uris = (Set) printerAttributes.get(PrinterUriSupported.class); + PrinterUriSupported uri = (PrinterUriSupported) uris.toArray()[0]; + + IppPrintService service + = new CupsPrintService(uri.getURI(), username, password); + + return service; + } + + /** + * Requests all printers from this CUPS server. + * + * @return The list of available printers. + * @throws IppException if problems during request/response processing occur. + */ + public List getAllPrinters() throws IppException + { + IppResponse response = null; + + try + { + IppRequest request = new IppRequest(uri, username, password); + request.setOperationID((short)CupsIppOperation.CUPS_GET_PRINTERS); + request.setOperationAttributeDefaults(); + + RequestedAttributes requestedAttrs + = new RequestedAttributes("printer-uri-supported"); + request.addOperationAttribute(requestedAttrs); + + response = request.send(); + } + catch (IOException e) + { + throw new IppException("IOException in IPP request/response.", e); + } + + List prAttr = response.getPrinterAttributes(); + List services = new ArrayList(); + + for (int i=0; i < prAttr.size(); i++) + { + Map printerAttributes = (Map) prAttr.get(i); + Set uris = (Set) printerAttributes.get(PrinterUriSupported.class); + PrinterUriSupported uri = (PrinterUriSupported) uris.toArray()[0]; + + try + { + CupsPrintService cups = new CupsPrintService(uri.getURI(), + username, password); + services.add(cups); + } + catch (IppException e) + { + // do nothing, we only catch the IppException which could be + // thrown during instantiation as single printers may be discovered + // correctly but not usable due to other security restrictions + } + } + + return services; + } + + /** + * Requests all classes from this CUPS server. Classes in cups are + * collections of printers. This means jobs directed to a class + * are forwarded to the first available printer of the collection. + * + * @return The list of available classes. + * @throws IppException if problems during request/response processing occur. + */ + public List getAllClasses() throws IppException + { + IppResponse response = null; + + try + { + IppRequest request = new IppRequest(uri, username, password); + request.setOperationID((short)CupsIppOperation.CUPS_GET_CLASSES); + request.setOperationAttributeDefaults(); + + RequestedAttributes requestedAttrs + = new RequestedAttributes("printer-uri-supported"); + request.addOperationAttribute(requestedAttrs); + + response = request.send(); + } + catch (IOException e) + { + throw new IppException("IOException in IPP request/response.", e); + } + + List prAttr = response.getPrinterAttributes(); + List services = new ArrayList(); + + for (int i=0; i < prAttr.size(); i++) + { + Map printerAttributes = (Map) prAttr.get(i); + Set uris = (Set) printerAttributes.get(PrinterUriSupported.class); + PrinterUriSupported uri = (PrinterUriSupported) uris.toArray()[0]; + + try + { + CupsPrintService cups = new CupsPrintService(uri.getURI(), + username, password); + services.add(cups); + } + catch (IppException e) + { + // do nothing, we only catch the IppException which could be + // thrown during instantiation as single printers may be discovered + // correctly but not usable due to other security restrictions + } + } + + return services; + } + +} diff --git a/libjava/classpath/gnu/javax/print/PrintAttributeException.java b/libjava/classpath/gnu/javax/print/PrintAttributeException.java new file mode 100644 index 000000000..5bcc59fc9 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/PrintAttributeException.java @@ -0,0 +1,148 @@ +/* PrintAttributeException.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print; + +import javax.print.AttributeException; +import javax.print.PrintException; +import javax.print.attribute.Attribute; + +/** + * A PrintException further refining the exception + * cause by providing an implementation of the print exception + * interface AttributeException. + * + * @see javax.print.PrintException + * @see javax.print.AttributeException + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class PrintAttributeException extends PrintException + implements AttributeException +{ + private Class[] categories; + private Attribute[] values; + + /** + * Constructs a PrintAttributeException + * with the given unsupported attributes and/or values. + * + * @param unsupportedAttributes the unsupported categories, + * may be null. + * @param unsupportedValues the unsupported attribute values, + * may be null. + */ + public PrintAttributeException(Class[] unsupportedAttributes, + Attribute[] unsupportedValues) + { + super(); + categories = unsupportedAttributes; + values = unsupportedValues; + } + + /** + * Constructs a PrintAttributeException + * with the given unsupported attributes and/or values. + * + * @param e chained exception + * @param unsupportedAttributes the unsupported categories, + * may be null. + * @param unsupportedValues the unsupported attribute values, + * may be null. + */ + public PrintAttributeException(Exception e, + Class[] unsupportedAttributes, Attribute[] unsupportedValues) + { + super(e); + categories = unsupportedAttributes; + values = unsupportedValues; + } + + /** + * Constructs a PrintAttributeException + * with the given unsupported attributes and/or values. + * + * @param s detailed message + * @param unsupportedAttributes the unsupported categories, + * may be null. + * @param unsupportedValues the unsupported attribute values, + * may be null. + */ + public PrintAttributeException(String s, + Class[] unsupportedAttributes, Attribute[] unsupportedValues) + { + super(s); + categories = unsupportedAttributes; + values = unsupportedValues; + } + + /** + * Constructs a PrintAttributeException + * with the given unsupported attributes and/or values. + * + * @param s detailed message + * @param e chained exception + * @param unsupportedAttributes the unsupported categories, + * may be null. + * @param unsupportedValues the unsupported attribute values, + * may be null. + */ + public PrintAttributeException(String s, Exception e, + Class[] unsupportedAttributes, Attribute[] unsupportedValues) + { + super(s, e); + categories = unsupportedAttributes; + values = unsupportedValues; + } + + /** + * @see AttributeException#getUnsupportedAttributes() + */ + public Class[] getUnsupportedAttributes() + { + return categories; + } + + /** + * @see AttributeException#getUnsupportedValues() + */ + public Attribute[] getUnsupportedValues() + { + return values; + } +} diff --git a/libjava/classpath/gnu/javax/print/PrintFlavorException.java b/libjava/classpath/gnu/javax/print/PrintFlavorException.java new file mode 100644 index 000000000..a9342db96 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/PrintFlavorException.java @@ -0,0 +1,120 @@ +/* PrintFlavorException.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print; + +import javax.print.DocFlavor; +import javax.print.FlavorException; +import javax.print.PrintException; + +/** + * A PrintException further refining the exception + * cause by providing an implementation of the print exception + * interface FlavorException. + * + * @see javax.print.PrintException + * @see javax.print.FlavorException + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public class PrintFlavorException extends PrintException + implements FlavorException +{ + private DocFlavor[] flavors; + + /** + * Constructs a PrintFlavorException + * with the given unsupported doc flavor array + * + * @param unsupportedFlavors the unsupported document flavors. + */ + public PrintFlavorException(DocFlavor[] unsupportedFlavors) + { + super(); + flavors = unsupportedFlavors; + } + + /** + * Constructs a PrintFlavorException + * with the given unsupported doc flavor array + * + * @param e chained exception + * @param unsupportedFlavors the unsupported document flavors. + */ + public PrintFlavorException(Exception e, DocFlavor[] unsupportedFlavors) + { + super(e); + flavors = unsupportedFlavors; + } + + /** + * Constructs a PrintFlavorException + * with the given unsupported doc flavor array + * + * @param s detailed message + * @param unsupportedFlavors the unsupported document flavors. + */ + public PrintFlavorException(String s, DocFlavor[] unsupportedFlavors) + { + super(s); + flavors = unsupportedFlavors; + } + + /** + * Constructs a PrintFlavorException + * with the given unsupported doc flavor array + * + * @param s detailed message + * @param e chained exception + * @param unsupportedFlavors the unsupported document flavors. + */ + public PrintFlavorException(String s, Exception e, + DocFlavor[] unsupportedFlavors) + { + super(s, e); + flavors = unsupportedFlavors; + } + + /** + * @see FlavorException#getUnsupportedFlavors() + */ + public DocFlavor[] getUnsupportedFlavors() + { + return flavors; + } +} diff --git a/libjava/classpath/gnu/javax/print/PrintUriException.java b/libjava/classpath/gnu/javax/print/PrintUriException.java new file mode 100644 index 000000000..9c13c132a --- /dev/null +++ b/libjava/classpath/gnu/javax/print/PrintUriException.java @@ -0,0 +1,140 @@ +/* PrintUriException.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print; + +import java.net.URI; + +import javax.print.PrintException; +import javax.print.URIException; + +/** + * A PrintException further refining the exception + * cause by providing an implementation of the print exception + * interface URIException. + * + * @see javax.print.PrintException + * @see javax.print.URIException + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class PrintUriException extends PrintException + implements URIException +{ + private int reason; + private URI uri; + + /** + * Constructs a PrintUriException with the given reason + * and unsupported URI instance. + * + * @param reason the reason for the exception. + * @param unsupportedUri the URI which is unsupported. + * + * @see URIException + */ + public PrintUriException(int reason, URI unsupportedUri) + { + super(); + this.reason = reason; + uri = unsupportedUri; + } + + /** + * Constructs a PrintUriException with the given reason + * and unsupported URI instance. + * + * @param e chained exception + * @param reason the reason for the exception. + * @param unsupportedUri the URI which is unsupported. + */ + public PrintUriException(Exception e, int reason, URI unsupportedUri) + { + super(e); + this.reason = reason; + uri = unsupportedUri; + } + + /** + * Constructs a PrintUriException with the given reason + * and unsupported URI instance. + * + * @param s detailed message + * @param reason the reason for the exception. + * @param unsupportedUri the URI which is unsupported. + */ + public PrintUriException(String s, int reason, URI unsupportedUri) + { + super(s); + this.reason = reason; + uri = unsupportedUri; + } + + /** + * Constructs a PrintUriException with the given reason + * and unsupported URI instance. + * + * @param s detailed message + * @param e chained exception + * @param reason the reason for the exception. + * @param unsupportedUri the URI which is unsupported. + */ + public PrintUriException(String s, Exception e, + int reason, URI unsupportedUri) + { + super(s, e); + this.reason = reason; + uri = unsupportedUri; + } + + /** + * @see URIException#getReason() + */ + public int getReason() + { + return reason; + } + + /** + * @see URIException#getUnsupportedURI() + */ + public URI getUnsupportedURI() + { + return uri; + } +} diff --git a/libjava/classpath/gnu/javax/print/PrinterDialog.java b/libjava/classpath/gnu/javax/print/PrinterDialog.java new file mode 100644 index 000000000..6557baf4f --- /dev/null +++ b/libjava/classpath/gnu/javax/print/PrinterDialog.java @@ -0,0 +1,1722 @@ +/* PrinterDialog.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.print; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.GraphicsConfiguration; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.HeadlessException; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.util.ArrayList; +import java.util.ResourceBundle; + +import javax.print.DocFlavor; +import javax.print.PrintService; +import javax.print.attribute.Attribute; +import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.PrintRequestAttributeSet; +import javax.print.attribute.standard.Chromaticity; +import javax.print.attribute.standard.Copies; +import javax.print.attribute.standard.Destination; +import javax.print.attribute.standard.JobName; +import javax.print.attribute.standard.JobPriority; +import javax.print.attribute.standard.JobSheets; +import javax.print.attribute.standard.Media; +import javax.print.attribute.standard.MediaPrintableArea; +import javax.print.attribute.standard.OrientationRequested; +import javax.print.attribute.standard.PageRanges; +import javax.print.attribute.standard.PrintQuality; +import javax.print.attribute.standard.PrinterInfo; +import javax.print.attribute.standard.PrinterIsAcceptingJobs; +import javax.print.attribute.standard.PrinterMakeAndModel; +import javax.print.attribute.standard.PrinterState; +import javax.print.attribute.standard.RequestingUserName; +import javax.print.attribute.standard.SheetCollate; +import javax.print.attribute.standard.Sides; +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.ButtonGroup; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.JSpinner; +import javax.swing.JTabbedPane; +import javax.swing.JTextField; +import javax.swing.SpinnerNumberModel; +import javax.swing.border.TitledBorder; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +/** + * Implementation of the PrinterDialog used by + * {@link javax.print.ServiceUI} for visual selection + * of print services and its attributes. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class PrinterDialog extends JDialog implements ActionListener +{ + + /** + * The General Panel used in the printing dialog. + * @author Wolfgang Baer (WBaer@gmx.de) + */ + final class GeneralPanel extends JPanel + { + /** + * Handles the copies attribute. + * @author Wolfgang Baer (WBaer@gmx.de) + */ + final class CopiesAndSorted extends JPanel + implements ChangeListener, ActionListener + { + private JCheckBox sort; + private JSpinner copies; + private JLabel copies_lb; + private SpinnerNumberModel copiesModel; + + CopiesAndSorted() + { + copies_lb = new JLabel(getLocalizedString("lb.copies")); + sort = new JCheckBox(getLocalizedString("cb.sort")); + sort.addActionListener(this); + + copiesModel = new SpinnerNumberModel(1, 1, 9999, 1); + copies = new JSpinner(copiesModel); + copies.addChangeListener(this); + + GridBagLayout layout = new GridBagLayout(); + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.BOTH; + c.insets = new Insets(5, 5, 5, 5); + + setLayout(layout); + setBorder(new TitledBorder(getLocalizedString("title.copies"))); + + c.anchor = GridBagConstraints.WEST; + + c.gridx = 0; + c.gridy = 0; + add(copies_lb, c); + + c.gridx = 1; + c.gridy = 0; + add(copies, c); + + c.gridx = 0; + c.gridy = 1; + add(sort, c); + } + + // copies jspinner state + public void stateChanged(ChangeEvent event) + { + int value = ((Integer) copies.getValue()).intValue(); + atts.add(new Copies(value)); + + if (value > 1 && categorySupported(SheetCollate.class)) + sort.setEnabled(true); + else + sort.setEnabled(false); + } + + // sorted checkbox state + public void actionPerformed(ActionEvent event) + { + if (sort.isSelected()) + atts.add(SheetCollate.COLLATED); + } + + /** + * Called to update for new selected + * print service. Tests if currently + * selected attributes are supported. + */ + void updateForSelectedService() + { + if (categorySupported(Copies.class)) + { + copies.setEnabled(true); + copies_lb.setEnabled(true); + + Copies copies = (Copies) attribute(Copies.class); + if (copies != null) + copiesModel.setValue(new Integer(copies.getValue())); + + if (((Integer)copiesModel.getValue()).intValue() > 1 + && categorySupported(SheetCollate.class)) + { + sort.setEnabled(true); + Attribute collate = attribute(SheetCollate.class); + if (collate != null && collate.equals(SheetCollate.COLLATED)) + sort.setSelected(true); + } + else + sort.setEnabled(false); + } + else + { + copies.setEnabled(false); + copies_lb.setEnabled(false); + } + } + } + + /** + * Handles the print ranges attribute. + * @author Wolfgang Baer (WBaer@gmx.de) + */ + final class PrintRange extends JPanel + implements ActionListener, FocusListener + { + private JLabel to; + private JRadioButton all_rb, pages_rb; + private JTextField from_tf, to_tf; + + PrintRange() + { + to = new JLabel(getLocalizedString("lb.to")); + to.setEnabled(false); + + all_rb = new JRadioButton(getLocalizedString("rbt.all")); + all_rb.setSelected(true); + all_rb.setActionCommand("ALL"); + all_rb.addActionListener(this); + pages_rb = new JRadioButton(getLocalizedString("rbt.pages")); + pages_rb.setActionCommand("PAGES"); + pages_rb.setEnabled(false); + pages_rb.addActionListener(this); + + ButtonGroup group = new ButtonGroup(); + group.add(all_rb); + group.add(pages_rb); + + from_tf = new JTextField("1", 4); + from_tf.setEnabled(false); + from_tf.addFocusListener(this); + to_tf = new JTextField("1", 4); + to_tf.setEnabled(false); + to_tf.addFocusListener(this); + + GridBagLayout layout = new GridBagLayout(); + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.BOTH; + + setLayout(layout); + setBorder(new TitledBorder(getLocalizedString("title.printrange"))); + + c.insets = new Insets(15, 5, 5, 5); + c.gridx = 0; + c.gridy = 0; + add(all_rb, c); + + c.insets = new Insets(5, 5, 15, 5); + c.gridx = 0; + c.gridy = 1; + add(pages_rb, c); + + c.gridx = 1; + c.gridy = 1; + add(from_tf, c); + + c.gridx = 2; + c.gridy = 1; + add(to, c); + + c.insets = new Insets(5, 5, 15, 15); + c.gridx = 3; + c.gridy = 1; + add(to_tf, c); + } + + // focus pagerange + public void focusGained(FocusEvent event) + { + updatePageRanges(); + } + + public void focusLost(FocusEvent event) + { + updatePageRanges(); + } + + // updates the range after user changed it + private void updatePageRanges() + { + int lower = Integer.parseInt(from_tf.getText()); + int upper = Integer.parseInt(to_tf.getText()); + + if (lower > upper) + { + upper = lower; + to_tf.setText("" + lower); + } + + PageRanges range = new PageRanges(lower, upper); + atts.add(range); + } + + // page range change + public void actionPerformed(ActionEvent e) + { + // if ALL is selected we must use a full-range object + if (e.getActionCommand().equals("ALL")) + { + from_tf.setEnabled(false); + to.setEnabled(false); + to_tf.setEnabled(false); + + atts.add(new PageRanges(1, Integer.MAX_VALUE)); + } + else + { + from_tf.setEnabled(true); + to.setEnabled(true); + to_tf.setEnabled(true); + all_rb.setSelected(false); + } + } + + /** + * Called to update for new selected + * print service. Tests if currently + * selected attributes are supported. + */ + void updateForSelectedService() + { + if (categorySupported(PageRanges.class)) + { + pages_rb.setEnabled(true); + PageRanges range = (PageRanges) attribute(PageRanges.class); + if (range != null) + { + from_tf.setEnabled(true); + to.setEnabled(true); + to_tf.setEnabled(true); + all_rb.setSelected(false); + pages_rb.setSelected(true); + + int[][] members = range.getMembers(); + // Although passed in attributes may contain more than one + // range we only take the first one + from_tf.setText("" + members[0][0]); + to_tf.setText("" + members[0][1]); + } + } + else + { + from_tf.setEnabled(false); + to.setEnabled(false); + to_tf.setEnabled(false); + all_rb.setSelected(true); + } + } + } + + /** + * Handles the selection of the print services + * and its location and description attributes. + * @author Wolfgang Baer (WBaer@gmx.de) + */ + final class PrintServices extends JPanel + implements ActionListener + { + private JLabel name, status, typ, info; + private JLabel statusValue, typValue, infoValue; + private JButton attributes; + private JComboBox services_cob; + private JCheckBox fileRedirection_cb; + + PrintServices() + { + name = new JLabel(getLocalizedString("lb.name")); + status = new JLabel(getLocalizedString("lb.status")); + typ = new JLabel(getLocalizedString("lb.typ")); + info = new JLabel(getLocalizedString("lb.info")); + typValue = new JLabel(); + infoValue = new JLabel(); + statusValue = new JLabel(); + + attributes = new JButton(getLocalizedString("bt.attributes")); + attributes.setEnabled(false); + attributes.setActionCommand("ATTRIBUTES"); + attributes.addActionListener(this); + + services_cob = new JComboBox(getPrintServices()); + services_cob.setActionCommand("SERVICE"); + services_cob.addActionListener(this); + + fileRedirection_cb = new JCheckBox(getLocalizedString("cb.output")); + fileRedirection_cb.setEnabled(false); + + GridBagLayout layout = new GridBagLayout(); + GridBagConstraints c = new GridBagConstraints(); + + setLayout(layout); + setBorder(new TitledBorder(getLocalizedString("title.printservice"))); + + c.insets = new Insets(5, 5, 5, 5); + c.anchor = GridBagConstraints.LINE_END; + c.gridx = 0; + c.gridy = 0; + add(name, c); + + c.gridx = 0; + c.gridy = 1; + add(status, c); + + c.gridx = 0; + c.gridy = 2; + add(typ, c); + + c.gridx = 0; + c.gridy = 3; + add(info, c); + + c.gridx = 2; + c.gridy = 3; + c.weightx = 1; + add(fileRedirection_cb, c); + + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + c.gridx = 1; + c.gridy = 0; + c.weightx = 1.5; + add(services_cob, c); + + c.gridx = 1; + c.gridy = 1; + c.gridwidth = 2; + c.weightx = 1; + add(statusValue, c); + + c.gridx = 1; + c.gridy = 2; + c.gridwidth = 2; + c.weightx = 1; + add(typValue, c); + + c.gridx = 1; + c.gridy = 3; + c.gridwidth = 2; + c.weightx = 1; + add(infoValue, c); + + c.gridx = 2; + c.gridy = 0; + c.weightx = 1.5; + add(attributes, c); + } + + public void actionPerformed(ActionEvent e) + { + if (e.getActionCommand().equals("SERVICE")) + { + setSelectedPrintService((PrintService) services_cob.getSelectedItem()); + updateAll(); + } + else if (e.getActionCommand().equals("ATTRIBUTES")) + { + // TODO LowPriority-Enhancement: As tests have shown this button + // is even gray and not enabled under Windows - Its a good place + // to provide a classpath specific browsing dialog for all + // attributes not in the default printing dialog. + } + } + + /** + * Called to update for new selected + * print service. Tests if currently + * selected attributes are supported. + */ + void updateForSelectedService() + { + PrinterMakeAndModel att1 = + getSelectedPrintService().getAttribute(PrinterMakeAndModel.class); + typValue.setText(att1 == null ? "" : att1.getValue()); + + PrinterInfo att2 = + getSelectedPrintService().getAttribute(PrinterInfo.class); + infoValue.setText(att2 == null ? "" : att2.getValue()); + + PrinterIsAcceptingJobs att3 = + getSelectedPrintService().getAttribute(PrinterIsAcceptingJobs.class); + PrinterState att4 = + getSelectedPrintService().getAttribute(PrinterState.class); + + String status = att4.toString(); + if (att3 == PrinterIsAcceptingJobs.ACCEPTING_JOBS) + status += " - " + getLocalizedString("lb.acceptingjobs"); + else if (att3 == PrinterIsAcceptingJobs.NOT_ACCEPTING_JOBS) + status += " - " + getLocalizedString("lb.notacceptingjobs"); + + statusValue.setText(status); + + if (categorySupported(Destination.class)) + { + fileRedirection_cb.setEnabled(false); + } + } + + } + + private PrintServices printserv_panel; + private PrintRange printrange_panel; + private CopiesAndSorted copies; + + /** + * Constructs the General Panel. + */ + public GeneralPanel() + { + setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + + printserv_panel = new PrintServices(); + printrange_panel = new PrintRange(); + copies = new CopiesAndSorted(); + + JPanel layout_panel = new JPanel(); + layout_panel.setLayout(new BoxLayout(layout_panel, BoxLayout.LINE_AXIS)); + layout_panel.add(printrange_panel); + layout_panel.add(Box.createRigidArea(new Dimension(10, 0))); + layout_panel.add(copies); + + setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); + add(printserv_panel); + add(Box.createRigidArea(new Dimension(0, 12))); + add(layout_panel); + } + + /** + * Calls update on all internal panels to adjust + * for a new selected print service. + */ + void update() + { + printserv_panel.updateForSelectedService(); + printrange_panel.updateForSelectedService(); + copies.updateForSelectedService(); + } + } + + /** + * The Page setup Panel. + * @author Wolfgang Baer (WBaer@gmx.de) + */ + final class PageSetupPanel extends JPanel + { + /** + * Handles the orientation attribute. + * @author Wolfgang Baer (WBaer@gmx.de) + */ + final class Orientation extends JPanel implements ActionListener + { + private JRadioButton portrait, landscape, rev_portrait, rev_landscape; + + Orientation() + { + portrait = new JRadioButton(getLocalizedString("rbt.portrait")); + portrait.addActionListener(this); + landscape = new JRadioButton(getLocalizedString("rbt.landscape")); + landscape.addActionListener(this); + rev_portrait = new JRadioButton(getLocalizedString("rbt.revportrait")); + rev_portrait.addActionListener(this); + rev_landscape = new JRadioButton(getLocalizedString("rbt.revlandscape")); + rev_landscape.addActionListener(this); + + ButtonGroup group = new ButtonGroup(); + group.add(portrait); + group.add(landscape); + group.add(rev_portrait); + group.add(rev_landscape); + + GridBagLayout layout = new GridBagLayout(); + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.BOTH; + + setLayout(layout); + setBorder(new TitledBorder(getLocalizedString("title.orientation"))); + + c.insets = new Insets(5, 5, 5, 5); + c.gridx = 0; + c.gridy = 0; + add(portrait, c); + + c.gridx = 0; + c.gridy = 1; + add(landscape, c); + + c.gridx = 0; + c.gridy = 2; + add(rev_portrait, c); + + c.gridx = 0; + c.gridy = 3; + add(rev_landscape, c); + } + + // event handling orientation + public void actionPerformed(ActionEvent e) + { + if (e.getSource() == portrait) + atts.add(OrientationRequested.PORTRAIT); + else if (e.getSource() == landscape) + atts.add(OrientationRequested.LANDSCAPE); + else if (e.getSource() == rev_portrait) + atts.add(OrientationRequested.REVERSE_PORTRAIT); + else + atts.add(OrientationRequested.REVERSE_LANDSCAPE); + } + + /** + * Called to update for new selected + * print service. Tests if currently + * selected attributes are supported. + */ + void updateForSelectedService() + { + if (categorySupported(OrientationRequested.class)) + { + portrait.setEnabled(true); + landscape.setEnabled(true); + rev_landscape.setEnabled(true); + rev_portrait.setEnabled(true); + + Attribute orientation = attribute(OrientationRequested.class); + if (orientation != null) + { + if (orientation.equals(OrientationRequested.LANDSCAPE)) + landscape.setSelected(true); + else if (orientation.equals(OrientationRequested.PORTRAIT)) + portrait.setSelected(true); + else if (orientation.equals(OrientationRequested.REVERSE_PORTRAIT)) + rev_portrait.setSelected(true); + else + rev_landscape.setSelected(true); + } + else + { + Object defaultValue = defaultValue(OrientationRequested.class); + if (defaultValue.equals(OrientationRequested.LANDSCAPE)) + landscape.setSelected(true); + else if (defaultValue.equals(OrientationRequested.PORTRAIT)) + portrait.setSelected(true); + else if (defaultValue.equals(OrientationRequested.REVERSE_PORTRAIT)) + rev_portrait.setSelected(true); + else + rev_landscape.setSelected(true); + } + } + else + { + portrait.setEnabled(false); + landscape.setEnabled(false); + rev_landscape.setEnabled(false); + rev_portrait.setEnabled(false); + } + } + } + + /** + * Handles the media attribute. + * @author Wolfgang Baer (WBaer@gmx.de) + */ + final class MediaTypes extends JPanel implements ActionListener + { + private JLabel size_lb, source_lb; + private JComboBox size, source; + + MediaTypes() + { + size_lb = new JLabel(getLocalizedString("lb.size")); + source_lb = new JLabel(getLocalizedString("lb.source")); + + size = new JComboBox(); + size.setEditable(false); + size.addActionListener(this); + source = new JComboBox(); + source.setEditable(false); + size.addActionListener(this); + + GridBagLayout layout = new GridBagLayout(); + GridBagConstraints c = new GridBagConstraints(); + + setLayout(layout); + setBorder(new TitledBorder(getLocalizedString("title.medias"))); + + c.insets = new Insets(5, 5, 5, 5); + c.anchor = GridBagConstraints.LINE_END; + c.gridx = 0; + c.gridy = 0; + add(size_lb, c); + + c.gridx = 0; + c.gridy = 1; + add(source_lb, c); + + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + c.gridx = 1; + c.gridy = 0; + c.weightx = 1.5; + add(size, c); + + c.gridx = 1; + c.gridy = 1; + c.weightx = 1.5; + add(source, c); + } + + public void actionPerformed(ActionEvent event) + { + if (event.getSource() == size) + { + Object obj = size.getSelectedItem(); + if (obj instanceof Media) + atts.add((Media) obj); + } + + // we ignore source events currently + // as only the automatic selection is used. + } + + /** + * Called to update for new selected + * print service. Tests if currently + * selected attributes are supported. + */ + void updateForSelectedService() + { + if (categorySupported(Media.class)) + { + Media[] medias = (Media[]) getSelectedPrintService() + .getSupportedAttributeValues(Media.class, flavor, null); + + size.removeAllItems(); + if (medias.length == 0) + size.addItem(getLocalizedString("lb.automatically")); + else + for (int i=0; i < medias.length; i++) + size.addItem(medias[i]); + + Media media = (Media) attribute(Media.class); + if (media != null) + size.setSelectedItem(media); + + // this is currently ignored + source.removeAllItems(); + source.addItem(getLocalizedString("lb.automatically")); + } + else + { + size.removeAllItems(); + source.removeAllItems(); + + size.addItem(getLocalizedString("lb.automatically")); + source.addItem(getLocalizedString("lb.automatically")); + } + } + } + + /** + * Handles the media printable area attribute. + * @author Wolfgang Baer (WBaer@gmx.de) + */ + final class Margins extends JPanel implements FocusListener + { + private JLabel left, right, top, bottom; + private JTextField left_tf, right_tf, top_tf, bottom_tf; + + Margins() + { + left = new JLabel(getLocalizedString("lb.left")); + right = new JLabel(getLocalizedString("lb.right")); + top = new JLabel(getLocalizedString("lb.top")); + bottom = new JLabel(getLocalizedString("lb.bottom")); + + left_tf = new JTextField(7); + left_tf.addFocusListener(this); + right_tf = new JTextField(7); + right_tf.addFocusListener(this); + top_tf = new JTextField(7); + top_tf.addFocusListener(this); + bottom_tf = new JTextField(7); + bottom_tf.addFocusListener(this); + + GridBagLayout layout = new GridBagLayout(); + GridBagConstraints c = new GridBagConstraints(); + + setLayout(layout); + setBorder(new TitledBorder(getLocalizedString("title.margins"))); + + c.insets = new Insets(5, 5, 5, 5); + c.gridx = 0; + c.gridy = 0; + add(left, c); + + c.gridx = 1; + c.gridy = 0; + add(right, c); + + c.insets = new Insets(5, 5, 5, 5); + c.gridx = 0; + c.gridy = 1; + add(left_tf, c); + + c.gridx = 1; + c.gridy = 1; + add(right_tf, c); + + c.insets = new Insets(10, 5, 5, 5); + c.gridx = 0; + c.gridy = 2; + add(top, c); + + c.gridx = 1; + c.gridy = 2; + add(bottom, c); + + c.insets = new Insets(0, 5, 5, 5); + c.gridx = 0; + c.gridy = 3; + add(top_tf, c); + + c.gridx = 1; + c.gridy = 3; + add(bottom_tf, c); + } + + public void focusGained(FocusEvent event) + { + updateMargins(); + } + + public void focusLost(FocusEvent event) + { + updateMargins(); + } + + // updates the margins after user changed it + private void updateMargins() + { + // We currently do not support this attribute + // as it is not in the IPP spec and therefore not in CUPS + } + + /** + * Called to update for new selected + * print service. Tests if currently + * selected attributes are supported. + */ + void updateForSelectedService() + { + if (categorySupported(MediaPrintableArea.class)) + { + left.setEnabled(true); + right.setEnabled(true); + top.setEnabled(true); + bottom.setEnabled(true); + left_tf.setEnabled(true); + right_tf.setEnabled(true); + top_tf.setEnabled(true); + bottom_tf.setEnabled(true); + } + else + { + left.setEnabled(false); + right.setEnabled(false); + top.setEnabled(false); + bottom.setEnabled(false); + left_tf.setEnabled(false); + right_tf.setEnabled(false); + top_tf.setEnabled(false); + bottom_tf.setEnabled(false); + } + } + } + + private MediaTypes media_panel; + private Orientation orientation_panel; + private Margins margins_panel; + + /** + * Constructs the page setup user interface. + */ + public PageSetupPanel() + { + setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + + media_panel = new MediaTypes(); + orientation_panel = new Orientation(); + margins_panel = new Margins(); + + JPanel layout_panel = new JPanel(); + layout_panel.setLayout(new BoxLayout(layout_panel, BoxLayout.LINE_AXIS)); + layout_panel.add(orientation_panel); + layout_panel.add(Box.createRigidArea(new Dimension(10, 0))); + layout_panel.add(margins_panel); + + setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); + add(media_panel); + add(Box.createRigidArea(new Dimension(0, 12))); + add(layout_panel); + } + + /** + * Calls update on all internal panels to adjust + * for a new selected print service. + */ + void update() + { + media_panel.updateForSelectedService(); + orientation_panel.updateForSelectedService(); + margins_panel.updateForSelectedService(); + } + } + + /** + * The Appearance panel for quality, color etc. + * @author Wolfgang Baer (WBaer@gmx.de) + */ + final class AppearancePanel extends JPanel + { + /** + * Handles the print quality attribute. + * @author Wolfgang Baer (WBaer@gmx.de) + */ + final class Quality extends JPanel implements ActionListener + { + private JRadioButton low, normal, high; + private ButtonGroup group; + + Quality() + { + low = new JRadioButton(getLocalizedString("rbt.low")); + low.addActionListener(this); + normal = new JRadioButton(getLocalizedString("rbt.normal")); + normal.addActionListener(this); + high = new JRadioButton(getLocalizedString("rbt.high")); + high.addActionListener(this); + + group = new ButtonGroup(); + group.add(low); + group.add(normal); + group.add(high); + + GridBagLayout layout = new GridBagLayout(); + GridBagConstraints c = new GridBagConstraints(); + + setLayout(layout); + setBorder(new TitledBorder(getLocalizedString("title.quality"))); + + c.fill = GridBagConstraints.HORIZONTAL; + c.insets = new Insets(5, 5, 5, 5); + c.gridx = 0; + c.gridy = 0; + add(low, c); + + c.gridx = 0; + c.gridy = 1; + add(normal, c); + + c.gridx = 0; + c.gridy = 2; + add(high, c); + } + + public void actionPerformed(ActionEvent e) + { + if (e.getSource() == low) + atts.add(PrintQuality.DRAFT); + else if (e.getSource() == normal) + atts.add(PrintQuality.NORMAL); + else + atts.add(PrintQuality.HIGH); + } + + /** + * Called to update for new selected + * print service. Tests if currently + * selected attributes are supported. + */ + void updateForSelectedService() + { + if (categorySupported(PrintQuality.class)) + { + low.setEnabled(true); + normal.setEnabled(true); + high.setEnabled(true); + + Object defaultValue = defaultValue(PrintQuality.class); + Attribute quality = attribute(PrintQuality.class); + + if (quality != null) + { + if (quality.equals(PrintQuality.DRAFT)) + low.setSelected(true); + else if (quality.equals(PrintQuality.NORMAL)) + normal.setSelected(true); + else + high.setSelected(true); + } + else + { + if (defaultValue.equals(PrintQuality.DRAFT)) + low.setSelected(true); + else if (defaultValue.equals(PrintQuality.NORMAL)) + normal.setSelected(true); + else + high.setSelected(true); + } + } + else + { + low.setEnabled(false); + normal.setEnabled(false); + high.setEnabled(false); + } + } + } + + /** + * Handles the job attributes as requesting username, jobname etc. + * @author Wolfgang Baer (WBaer@gmx.de) + */ + final class JobAttributes extends JPanel + implements ActionListener, ChangeListener, FocusListener + { + private JLabel jobname, username, priority_lb; + private JTextField jobname_tf, username_tf; + private JCheckBox cover; + private JSpinner priority; + private SpinnerNumberModel model; + + JobAttributes() + { + jobname = new JLabel(getLocalizedString("lb.jobname")); + username = new JLabel(getLocalizedString("lb.username")); + priority_lb = new JLabel(getLocalizedString("lb.priority")); + + cover = new JCheckBox(getLocalizedString("cb.cover")); + cover.addActionListener(this); + + model = new SpinnerNumberModel(1, 1, 100, 1); + priority = new JSpinner(model); + priority.addChangeListener(this); + + jobname_tf = new JTextField(); + jobname_tf.addFocusListener(this); + username_tf = new JTextField(); + username_tf.addFocusListener(this); + + GridBagLayout layout = new GridBagLayout(); + GridBagConstraints c = new GridBagConstraints(); + + setLayout(layout); + setBorder(new TitledBorder(getLocalizedString("title.jobattributes"))); + + c.insets = new Insets(10, 5, 10, 5); + c.gridx = 0; + c.gridy = 0; + add(cover, c); + + c.anchor = GridBagConstraints.LINE_END; + c.gridx = 1; + c.gridy = 0; + c.weightx = 2; + add(priority_lb, c); + + c.gridx = 2; + c.gridy = 0; + c.weightx = 0.5; + add(priority, c); + + c.anchor = GridBagConstraints.LINE_END; + c.gridx = 0; + c.gridy = 1; + add(jobname, c); + + c.gridx = 0; + c.gridy = 2; + add(username, c); + + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.HORIZONTAL; + c.gridx = 1; + c.gridy = 1; + c.gridwidth = 2; + c.weightx = 1.5; + add(jobname_tf, c); + + c.insets = new Insets(10, 5, 15, 5); + c.gridx = 1; + c.gridy = 2; + add(username_tf, c); + } + + public void actionPerformed(ActionEvent event) + { + if (cover.isSelected()) + atts.add(JobSheets.STANDARD); + else + atts.add(JobSheets.NONE); + } + + public void stateChanged(ChangeEvent event) + { + int value = ((Integer) priority.getValue()).intValue(); + atts.add(new JobPriority(value)); + } + + public void focusGained(FocusEvent event) + { + updateTextfields(event); + } + + public void focusLost(FocusEvent event) + { + updateTextfields(event); + } + + private void updateTextfields(FocusEvent event) + { + if (event.getSource() == jobname_tf) + atts.add(new JobName(jobname_tf.getText(), null)); + else + atts.add(new RequestingUserName(username_tf.getText(), null)); + } + + /** + * Called to update for new selected + * print service. Tests if currently + * selected attributes are supported. + */ + void updateForSelectedService() + { + // JobPriority + if (categorySupported(JobPriority.class)) + { + JobPriority prio = (JobPriority) attribute(JobPriority.class); + JobPriority value = (JobPriority) defaultValue(JobPriority.class); + priority.setEnabled(true); + if (prio != null) + model.setValue(new Integer(prio.getValue())); + else + model.setValue(new Integer(value.getValue())); + } + else + priority.setEnabled(false); + + // Requesting username + if (categorySupported(RequestingUserName.class)) + { + Attribute user = attribute(RequestingUserName.class); + Object value = defaultValue(RequestingUserName.class); + username.setEnabled(true); + if (user != null) + username_tf.setText(user.toString()); + else + username_tf.setText(value.toString()); + } + else + username.setEnabled(false); + + // Job Name + if (categorySupported(JobName.class)) + { + Attribute job = attribute(JobName.class); + Object value = defaultValue(JobName.class); + jobname.setEnabled(true); + if (job != null) + jobname_tf.setText(job.toString()); + else + jobname_tf.setText(value.toString()); + } + else + jobname.setEnabled(false); + + // Job sheets + if (categorySupported(JobSheets.class)) + { + Attribute sheet = attribute(JobSheets.class); + Object value = defaultValue(JobSheets.class); + cover.setEnabled(true); + if (sheet != null) + { + if (sheet.equals(JobSheets.NONE)) + cover.setSelected(false); + else + cover.setSelected(true); + } + else + { + if (value.equals(JobSheets.NONE)) + cover.setSelected(false); + else + cover.setSelected(true); + } + } + else + cover.setEnabled(false); + } + } + + /** + * Handles the sides attributes. + * @author Wolfgang Baer (WBaer@gmx.de) + */ + final class SidesPanel extends JPanel implements ActionListener + { + private JRadioButton oneside, calendar, duplex; + + SidesPanel() + { + oneside = new JRadioButton(getLocalizedString("rbt.onesided")); + oneside.addActionListener(this); + calendar = new JRadioButton(getLocalizedString("rbt.calendar")); + calendar.addActionListener(this); + duplex = new JRadioButton(getLocalizedString("rbt.duplex")); + duplex.addActionListener(this); + + ButtonGroup group = new ButtonGroup(); + group.add(oneside); + group.add(calendar); + group.add(duplex); + + GridBagLayout layout = new GridBagLayout(); + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.BOTH; + + setLayout(layout); + setBorder(new TitledBorder(getLocalizedString("title.sides"))); + + c.insets = new Insets(5, 5, 5, 5); + c.gridx = 0; + c.gridy = 0; + add(oneside, c); + + c.gridx = 0; + c.gridy = 1; + add(calendar, c); + + c.gridx = 0; + c.gridy = 2; + add(duplex, c); + } + + public void actionPerformed(ActionEvent e) + { + if (e.getSource() == calendar) + atts.add(Sides.TWO_SIDED_SHORT_EDGE); + else if (e.getSource() == oneside) + atts.add(Sides.ONE_SIDED); + else + atts.add(Sides.TWO_SIDED_LONG_EDGE); + } + + /** + * Called to update for new selected + * print service. Tests if currently + * selected attributes are supported. + */ + void updateForSelectedService() + { + if (categorySupported(Sides.class)) + { + oneside.setEnabled(true); + calendar.setEnabled(true); + duplex.setEnabled(true); + + Object defaultValue = defaultValue(Sides.class); + Attribute sides = attribute(Sides.class); + if (sides != null) + { + if (sides.equals(Sides.TWO_SIDED_SHORT_EDGE)) + calendar.setSelected(true); + else if (sides.equals(Sides.ONE_SIDED)) + oneside.setSelected(true); + else + duplex.setSelected(true); + } + else + { + if (defaultValue.equals(Sides.TWO_SIDED_SHORT_EDGE)) + calendar.setSelected(true); + else if (defaultValue.equals(Sides.ONE_SIDED)) + oneside.setSelected(true); + else + duplex.setSelected(true); + } + } + else + { + oneside.setEnabled(false); + calendar.setEnabled(false); + duplex.setEnabled(false); + } + } + } + + /** + * Handles the chromaticity attributes. + * @author Wolfgang Baer (WBaer@gmx.de) + */ + final class Color extends JPanel implements ActionListener + { + private JRadioButton bw, color; + + Color() + { + bw = new JRadioButton(getLocalizedString("rbt.blackwhite")); + bw.addActionListener(this); + color = new JRadioButton(getLocalizedString("rbt.color")); + color.addActionListener(this); + + ButtonGroup group = new ButtonGroup(); + group.add(bw); + group.add(color); + + GridBagLayout layout = new GridBagLayout(); + GridBagConstraints c = new GridBagConstraints(); + + setLayout(layout); + setBorder(new TitledBorder(getLocalizedString("title.color"))); + + c.fill = GridBagConstraints.HORIZONTAL; + c.insets = new Insets(5, 5, 5, 5); + c.gridx = 0; + c.gridy = 0; + add(bw, c); + + c.gridx = 0; + c.gridy = 1; + add(color, c); + } + + public void actionPerformed(ActionEvent e) + { + if (e.getSource() == bw) + atts.add(Chromaticity.MONOCHROME); + else + atts.add(Chromaticity.COLOR); + } + + /** + * Called to update for new selected + * print service. Tests if currently + * selected attributes are supported. + */ + void updateForSelectedService() + { + if (categorySupported(Chromaticity.class)) + { + bw.setEnabled(true); + color.setEnabled(true); + + Object defaultValue = defaultValue(Chromaticity.class); + Attribute chromaticity = attribute(Chromaticity.class); + if (chromaticity != null) + { + if (chromaticity.equals(Chromaticity.MONOCHROME)) + bw.setSelected(true); + else + color.setSelected(true); + } + else + { + if (defaultValue.equals(Chromaticity.MONOCHROME)) + bw.setSelected(true); + else + color.setSelected(true); + } + } + else + { + bw.setEnabled(false); + color.setEnabled(false); + } + } + } + + private Quality quality_panel; + private JobAttributes jobAttr_panel; + private SidesPanel sides_panel; + private Color chromaticy_panel; + + /** + * Creates the panel for appearance attributes. + */ + public AppearancePanel() + { + setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + + quality_panel = new Quality(); + jobAttr_panel = new JobAttributes(); + sides_panel = new SidesPanel(); + chromaticy_panel = new Color(); + + JPanel layout_panel = new JPanel(); + layout_panel.setLayout(new BoxLayout(layout_panel, BoxLayout.LINE_AXIS)); + layout_panel.add(chromaticy_panel); + layout_panel.add(Box.createRigidArea(new Dimension(10, 0))); + layout_panel.add(quality_panel); + + JPanel layout2_panel = new JPanel(); + layout2_panel.setLayout(new BoxLayout(layout2_panel, BoxLayout.LINE_AXIS)); + layout2_panel.add(sides_panel); + layout2_panel.add(Box.createRigidArea(new Dimension(10, 0))); + layout2_panel.add(jobAttr_panel); + + setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); + add(layout_panel); + add(Box.createRigidArea(new Dimension(0, 12))); + add(layout2_panel); + } + + /** + * Calls update on all internal panels to adjust + * for a new selected print service. + */ + void update() + { + quality_panel.updateForSelectedService(); + jobAttr_panel.updateForSelectedService(); + sides_panel.updateForSelectedService(); + chromaticy_panel.updateForSelectedService(); + } + } + + // on main contentpane + private JButton ok_bt; + private JButton cancel_bt; + + // the tabs + private GeneralPanel general_panel; + private PageSetupPanel pagesetup_panel; + private AppearancePanel appearance_panel; + + private PrintService[] services; + private PrintService defaultService; + private PrintService selectedService; + private DocFlavor flavor; + private PrintRequestAttributeSet attributes; + + private boolean onlyPageDialog; + private PrintRequestAttributeSet atts; + + private final static ResourceBundle messages; + + static + { + messages = ResourceBundle.getBundle("gnu/javax/print/PrinterDialog"); + } + + // TODO LowPriority: Include checks so that if a specific value formerly + // selected is no more supported by the new service changes to the default. + + /** + * Class private constructs a printer dialog. + * + * @param gc the screen to use. null is default screen. + * @param services the print services to browse (not null). + * @param defaultService the default service. If null + * the first of the print services in the services array will be used. + * @param flavor the flavours to be printed. + * @param attributes the attributes requested. Will be updated + * by selections done by the user in the dialog. + * @param onlyPageDialog if true a page settings only dialog is constructed. + * + * @throws HeadlessException if GraphicsEnvironment is headless + */ + private PrinterDialog(GraphicsConfiguration gc, PrintService[] services, + PrintService defaultService, DocFlavor flavor, + PrintRequestAttributeSet attributes, boolean onlyPageDialog, String title) + throws HeadlessException + { + super((Frame)null, title, true, gc); + + setResizable(false); + setDefaultCloseOperation(DISPOSE_ON_CLOSE); + + // check and remove service not supporting the flavor + if (flavor != null) + { + ArrayList list = new ArrayList(services.length); + for(int i=0; i < services.length; i++) + if (services[i].isDocFlavorSupported(flavor)) + list.add(services[i]); + + if (defaultService != null + && (! list.contains(defaultService))) + defaultService = (PrintService) list.get(0); + + PrintService[] newServices = new PrintService[list.size()]; + this.services = (PrintService[]) list.toArray(newServices); + } + else + this.services = services; + + if (defaultService == null) + this.defaultService = services[0]; + else + this.defaultService = defaultService; + + this.selectedService = this.defaultService; + this.flavor = flavor; + + // the attributes given by the user + this.attributes = attributes; + // the one to work with during browsing + this.atts = new HashPrintRequestAttributeSet(attributes); + + this.onlyPageDialog = onlyPageDialog; + + initUI(onlyPageDialog); + pack(); + updateAll(); + } + + /** + * Constructs a page settings only dialog. + * + * @param gc the screen to use. null is default screen. + * @param service the print service for the page dialog. + * the first of the print services in the services array will be used. + * @param flavor the flavours to be printed. + * @param attributes the attributes requested. Will be updated + * by selections done by the user in the dialog. + * + * @throws HeadlessException if GraphicsEnvironment is headless + */ + public PrinterDialog(GraphicsConfiguration gc, PrintService service, + DocFlavor flavor, PrintRequestAttributeSet attributes) + throws HeadlessException + { + this(gc, new PrintService[] {service}, service, flavor, attributes, + true, getLocalizedString("title.pagedialog")); + } + + /** + * Constructs a printer dialog. + * + * @param gc the screen to use. null is default screen. + * @param services the print services to browse (not null). + * @param defaultService the default service. If null + * the first of the print services in the services array will be used. + * @param flavor the flavours to be printed. + * @param attributes the attributes requested. Will be updated + * by selections done by the user in the dialog. + * + * @throws HeadlessException if GraphicsEnvironment is headless + */ + public PrinterDialog(GraphicsConfiguration gc, PrintService[] services, + PrintService defaultService, DocFlavor flavor, + PrintRequestAttributeSet attributes) + throws HeadlessException + { + this(gc, services, defaultService, flavor, attributes, + false, getLocalizedString("title.printdialog")); + } + + // initializes the gui parts + private void initUI(boolean onlyPageDialog) + { + JPanel buttonPane = new JPanel(); + + if (onlyPageDialog) + { + JPanel pane = new JPanel(); + pane.setLayout(new BorderLayout()); + pagesetup_panel = new PageSetupPanel(); + pane.add(pagesetup_panel, BorderLayout.CENTER); + + ok_bt = new JButton(getLocalizedString("bt.OK")); + ok_bt.addActionListener(this); + cancel_bt = new JButton(getLocalizedString("bt.cancel")); + cancel_bt.addActionListener(this); + + getContentPane().add(pane, BorderLayout.CENTER); + } + else + { + general_panel = new GeneralPanel(); + pagesetup_panel = new PageSetupPanel(); + appearance_panel = new AppearancePanel(); + + JTabbedPane pane = new JTabbedPane(); + pane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + + ok_bt = new JButton(getLocalizedString("bt.print")); + ok_bt.addActionListener(this); + cancel_bt = new JButton(getLocalizedString("bt.cancel")); + cancel_bt.addActionListener(this); + + // populate jtabbedpane + pane.addTab(getLocalizedString("tab.general"), general_panel); + pane.addTab(getLocalizedString("tab.pagesetup"), pagesetup_panel); + pane.addTab(getLocalizedString("tab.appearance"), appearance_panel); + + // Put everything together + getContentPane().add(pane, BorderLayout.CENTER); + } + + buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS)); + buttonPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + buttonPane.add(Box.createHorizontalGlue()); + buttonPane.add(ok_bt); + buttonPane.add(Box.createRigidArea(new Dimension(5, 0))); + buttonPane.add(cancel_bt); + + getContentPane().add(buttonPane, BorderLayout.PAGE_END); + } + + /** + * Returns the modified attributes set. + * @return The attributes. + */ + public PrintRequestAttributeSet getAttributes() + { + return attributes; + } + + /** + * Returns the print service selected by the user. + * @return The selected print service. + */ + public PrintService getSelectedPrintService() + { + return selectedService; + } + + /** + * Sets the currently selected print service. + * + * @param service the service selected. + */ + protected void setSelectedPrintService(PrintService service) + { + selectedService = service; + } + + /** + * Returns the print service array. + * @return The print services. + */ + protected PrintService[] getPrintServices() + { + return services; + } + + /** + * Calls update on all panels to adjust + * for a new selected print service. + */ + void updateAll() + { + pagesetup_panel.update(); + + if (! onlyPageDialog) + { + general_panel.update(); + appearance_panel.update(); + } + } + + boolean categorySupported(Class category) + { + return getSelectedPrintService(). + isAttributeCategorySupported(category); + } + + Object defaultValue(Class category) + { + return getSelectedPrintService(). + getDefaultAttributeValue(category); + } + + Attribute attribute(Class category) + { + return atts.get(category); + } + + /** + * Action handler for Print/Cancel buttons. + * If cancel is pressed we reset the attributes + * and the selected service. + * + * @param e the ActionEvent + */ + public void actionPerformed(ActionEvent e) + { + if (e.getSource() == ok_bt) + { + setVisible(false); + attributes.addAll(atts); + dispose(); + } + else + { + setVisible(false); + selectedService = null; + dispose(); + } + } + + /** + * Retrieves localized messages from the resource bundle. + * + * @param key the key + * @return The localized value for the key. + */ + static final String getLocalizedString(String key) { + return messages.getString(key); + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/DocPrintJobImpl.java b/libjava/classpath/gnu/javax/print/ipp/DocPrintJobImpl.java new file mode 100644 index 000000000..8cfd6880d --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/DocPrintJobImpl.java @@ -0,0 +1,471 @@ +/* DocPrintJobImpl.java -- Implementation of DocPrintJob. + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp; + +import gnu.javax.print.PrintFlavorException; +import gnu.javax.print.ipp.attribute.job.JobId; +import gnu.javax.print.ipp.attribute.job.JobUri; +import gnu.javax.print.ipp.attribute.printer.DocumentFormat; +import gnu.javax.print.ipp.attribute.supported.OperationsSupported; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.print.CancelablePrintJob; +import javax.print.Doc; +import javax.print.DocFlavor; +import javax.print.DocPrintJob; +import javax.print.PrintException; +import javax.print.PrintService; +import javax.print.attribute.AttributeSetUtilities; +import javax.print.attribute.DocAttributeSet; +import javax.print.attribute.HashAttributeSet; +import javax.print.attribute.HashPrintJobAttributeSet; +import javax.print.attribute.PrintJobAttributeSet; +import javax.print.attribute.PrintRequestAttributeSet; +import javax.print.attribute.standard.JobName; +import javax.print.attribute.standard.PrinterURI; +import javax.print.attribute.standard.RequestingUserName; +import javax.print.event.PrintJobAttributeListener; +import javax.print.event.PrintJobEvent; +import javax.print.event.PrintJobListener; + +/** + * Implementation of the DocPrintJob interface. Implementation is + * specific to the IppPrintService implementation. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public class DocPrintJobImpl implements CancelablePrintJob +{ + /** The print service this job is bound to. */ + private IppPrintService service; + + /** The set of print job listeners. */ + private HashSet printJobListener = new HashSet(); + + /** The print job attributes listeners. */ + private ArrayList attributesListener = new ArrayList(); + /** The print job attributes listeners associated attribute set. */ + private ArrayList attributesListenerAttributes = new ArrayList(); + + /** The username. */ + private String username; + /** The password of the user. */ + private String password; + + /** Returned job uri. */ + private JobUri jobUri = null; + /** Returned job id. */ + private JobId jobId = null; + + /** The requesting-username for later canceling */ + private RequestingUserName requestingUser; + + /** The print job sets. */ + private PrintJobAttributeSet oldSet = new HashPrintJobAttributeSet(); + private PrintJobAttributeSet currentSet = new HashPrintJobAttributeSet(); + + /** + * State variable if we already started printing. + */ + private boolean printing = false; + + // TODO Implement complete PrintJobListener notification + // TODO Implement PrintJobAttributeListener notification + + /** + * Constructs a DocPrintJobImpl instance bound to the given print service. + * + * @param service the print service instance. + * @param user the user of this print service. + * @param passwd the password of the user. + */ + public DocPrintJobImpl(IppPrintService service, String user, String passwd) + { + this.service = service; + username = user; + password = passwd; + } + + /** + * @see DocPrintJob#addPrintJobAttributeListener(PrintJobAttributeListener, PrintJobAttributeSet) + */ + public void addPrintJobAttributeListener(PrintJobAttributeListener listener, + PrintJobAttributeSet attributes) + { + if (listener == null) + return; + + attributesListener.add(listener); + attributesListenerAttributes.add(attributes); + } + + /** + * @see DocPrintJob#addPrintJobListener(PrintJobListener) + */ + public void addPrintJobListener(PrintJobListener listener) + { + if (listener == null) + return; + + printJobListener.add(listener); + } + + /** + * @see javax.print.DocPrintJob#getAttributes() + */ + public PrintJobAttributeSet getAttributes() + { + return AttributeSetUtilities.unmodifiableView(currentSet); + } + + /** + * @see javax.print.DocPrintJob#getPrintService() + */ + public PrintService getPrintService() + { + return service; + } + + /** + * @see DocPrintJob#print(Doc, PrintRequestAttributeSet) + */ + public void print(Doc doc, PrintRequestAttributeSet attributes) + throws PrintException + { + if (printing) + throw new PrintException("already printing"); + + printing = true; + + DocAttributeSet docAtts = doc.getAttributes(); + DocFlavor flavor = doc.getDocFlavor(); + + if (flavor == null || (!service.isDocFlavorSupported(flavor))) + { + notifyPrintJobListeners(new PrintJobEvent(this, PrintJobEvent.JOB_FAILED)); + throw new PrintFlavorException("Invalid flavor", new DocFlavor[] {flavor}); + } + + // merge attributes as doc attributes take precendence + // over the print request attributes + HashAttributeSet mergedAtts = new HashAttributeSet(); + + if (attributes != null) + mergedAtts.addAll(attributes); + if (docAtts != null) + mergedAtts.addAll(docAtts); + + // check for requesting-user-name -add the + // executing username if no other is specified + // save user name so we can make a cancel operation under same user + if (! mergedAtts.containsKey(RequestingUserName.class)) + { + mergedAtts.add(IppPrintService.REQUESTING_USER_NAME); + requestingUser = IppPrintService.REQUESTING_USER_NAME; + } + else + { + requestingUser = (RequestingUserName) + mergedAtts.get(RequestingUserName.class); + } + + // same for job-name + if (! mergedAtts.containsKey(JobName.class)) + mergedAtts.add(IppPrintService.JOB_NAME); + + IppResponse response = null; + + try + { + PrinterURI printerUri = service.getPrinterURI(); + String printerUriStr = "http" + printerUri.toString().substring(3); + + URI uri = null; + try + { + uri = new URI(printerUriStr); + } + catch (URISyntaxException e) + { + // does not happen + } + + IppRequest request = + new IppRequest(uri, username, password); + + request.setOperationID( (short) OperationsSupported.PRINT_JOB.getValue()); + request.setOperationAttributeDefaults(); + request.addOperationAttribute(printerUri); + + if (mergedAtts != null) + { + request.addAndFilterJobOperationAttributes(mergedAtts); + request.addAndFilterJobTemplateAttributes(mergedAtts); + } + + // DocFlavor getMimeType returns charset quoted + DocumentFormat format = DocumentFormat.createDocumentFormat(flavor); + request.addOperationAttribute(format); + + // Get and set the printdata based on the + // representation classname + String className = flavor.getRepresentationClassName(); + + if (className.equals("[B")) + { + request.setData((byte[]) doc.getPrintData()); + response = request.send(); + } + else if (className.equals("java.io.InputStream")) + { + InputStream stream = (InputStream) doc.getPrintData(); + request.setData(stream); + response = request.send(); + stream.close(); + } + else if (className.equals("[C")) + { + try + { + // CUPS only supports UTF-8 currently so we convert + // We also assume that char[] is always utf-16 - correct ? + String str = new String((char[]) doc.getPrintData()); + request.setData(str.getBytes("utf-16")); + response = request.send(); + } + catch (UnsupportedEncodingException e) + { + notifyPrintJobListeners(new PrintJobEvent(this, PrintJobEvent.JOB_FAILED)); + throw new PrintFlavorException("Invalid charset of flavor", e, new DocFlavor[] {flavor}); + } + } + else if (className.equals("java.io.Reader")) + { + try + { + // FIXME Implement + // Convert a Reader into a InputStream properly encoded + response = request.send(); + throw new UnsupportedEncodingException("not supported yet"); + } + catch (UnsupportedEncodingException e) + { + notifyPrintJobListeners(new PrintJobEvent(this, PrintJobEvent.JOB_FAILED)); + throw new PrintFlavorException("Invalid charset of flavor", e, new DocFlavor[] {flavor}); + } + } + else if (className.equals("java.lang.String")) + { + try + { + // CUPS only supports UTF-8 currently so we convert + // We also assume that String is always utf-16 - correct ? + String str = (String) doc.getPrintData(); + request.setData(str.getBytes("utf-16")); + response = request.send(); + } + catch (UnsupportedEncodingException e) + { + notifyPrintJobListeners(new PrintJobEvent(this, PrintJobEvent.JOB_FAILED)); + throw new PrintFlavorException("Invalid charset of flavor", e, new DocFlavor[] {flavor}); + } + } + else if (className.equals("java.net.URL")) + { + URL url = (URL) doc.getPrintData(); + InputStream stream = url.openStream(); + request.setData(stream); + response = request.send(); + stream.close(); + } + else if (className.equals("java.awt.image.renderable.RenderableImage") + || className.equals("java.awt.print.Printable") + || className.equals("java.awt.print.Pageable")) + { + // For the future :-) + throw new PrintException("Not yet supported."); + } + else + { + // should not happen - however + notifyPrintJobListeners(new PrintJobEvent(this, PrintJobEvent.JOB_FAILED)); + throw new PrintFlavorException("Invalid flavor", new DocFlavor[] {flavor}); + } + + // at this point the data is transfered + notifyPrintJobListeners(new PrintJobEvent( + this, PrintJobEvent.DATA_TRANSFER_COMPLETE)); + } + catch (IOException e) + { + throw new PrintException("IOException occured.", e); + } + + int status = response.getStatusCode(); + if (! (status == IppStatusCode.SUCCESSFUL_OK + || status == IppStatusCode.SUCCESSFUL_OK_IGNORED_OR_SUBSTITUED_ATTRIBUTES + || status == IppStatusCode.SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES) ) + { + notifyPrintJobListeners(new PrintJobEvent( + this, PrintJobEvent.JOB_FAILED)); + throw new PrintException("Printing failed - received statuscode " + Integer.toHexString(status)); + + // TODO maybe specific status codes may require to throw a specific + // detailed attribute exception + } + else + { + // start print job progress monitoring thread + // FIXME Implement + + // for now we just notify as finished + notifyPrintJobListeners( + new PrintJobEvent(this, PrintJobEvent.JOB_COMPLETE)); + } + + List jobAtts = response.getJobAttributes(); + + // extract the uri and id of job for canceling and further monitoring + Map jobAttributes = (Map) jobAtts.get(0); + jobUri = (JobUri) ((HashSet)jobAttributes.get(JobUri.class)).toArray()[0]; + jobId = (JobId) ((HashSet)jobAttributes.get(JobId.class)).toArray()[0]; + } + + /** + * @see DocPrintJob#removePrintJobAttributeListener(PrintJobAttributeListener) + */ + public void removePrintJobAttributeListener(PrintJobAttributeListener listener) + { + if (listener == null) + return; + + int index = attributesListener.indexOf(listener); + if (index != -1) + { + attributesListener.remove(index); + attributesListenerAttributes.remove(index); + } + } + + /** + * @see DocPrintJob#removePrintJobListener(PrintJobListener) + */ + public void removePrintJobListener(PrintJobListener listener) + { + if (listener == null) + return; + + printJobListener.remove(listener); + } + + /** + * @see CancelablePrintJob#cancel() + */ + public void cancel() throws PrintException + { + if (jobUri == null) + { + throw new PrintException("print job is not yet send"); + } + + IppResponse response = null; + + try + { + IppRequest request = new IppRequest(jobUri.getURI(), username, password); + request.setOperationID( (short) OperationsSupported.CANCEL_JOB.getValue()); + request.setOperationAttributeDefaults(); + request.addOperationAttribute(jobUri); + request.addOperationAttribute(requestingUser); + response = request.send(); + } + catch (IOException e) + { + throw new IppException("IOException occured during cancel request.", e); + } + + int status = response.getStatusCode(); + if (! (status == IppStatusCode.SUCCESSFUL_OK + || status == IppStatusCode.SUCCESSFUL_OK_IGNORED_OR_SUBSTITUED_ATTRIBUTES + || status == IppStatusCode.SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES) ) + { + notifyPrintJobListeners(new PrintJobEvent( + this, PrintJobEvent.JOB_FAILED)); + throw new PrintException("Canceling failed - received statuscode " + Integer.toHexString(status)); + } + else + { + notifyPrintJobListeners(new PrintJobEvent( + this, PrintJobEvent.JOB_CANCELED)); + } + } + + private void notifyPrintJobListeners(PrintJobEvent e) + { + Iterator it = printJobListener.iterator(); + while (it.hasNext()) + { + PrintJobListener l = (PrintJobListener) it.next(); + if (e.getPrintEventType() == PrintJobEvent.DATA_TRANSFER_COMPLETE) + l.printDataTransferCompleted(e); + else if (e.getPrintEventType() == PrintJobEvent.JOB_CANCELED) + l.printJobCanceled(e); + else if (e.getPrintEventType() == PrintJobEvent.JOB_COMPLETE) + l.printJobCompleted(e); + else if (e.getPrintEventType() == PrintJobEvent.JOB_FAILED) + l.printJobFailed(e); + else if (e.getPrintEventType() == PrintJobEvent.NO_MORE_EVENTS) + l.printJobNoMoreEvents(e); + else + l.printJobRequiresAttention(e); + } + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/IppDelimiterTag.java b/libjava/classpath/gnu/javax/print/ipp/IppDelimiterTag.java new file mode 100644 index 000000000..1c074a8dd --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/IppDelimiterTag.java @@ -0,0 +1,99 @@ +/* IppDelimiterTag.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp; + + +/** + * IPP Delimiter Tags as described in RFC 2910 section 3.5.1. + *

    + * Every delimiter tag value can occur in the protocol field + * begin-attribute-group-tag and indicates that the following + * attributes will be part of the named group.
    + * The end-of-attributes-tag signals the end of the attributes + * section in the IPP request/response and therefore the beginning + * of the data section (if any). + *

    + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class IppDelimiterTag +{ + /** Start of the operation attributes group section. */ + public static final byte OPERATION_ATTRIBUTES_TAG = 0x01; + + /** Start of the job attributes group section. */ + public static final byte JOB_ATTRIBUTES_TAG = 0x02; + + /** End of the attributes section and begin of data section. */ + public static final byte END_OF_ATTRIBUTES_TAG = 0x03; + + /** Start of the printer attributes group section. */ + public static final byte PRINTER_ATTRIBUTES_TAG = 0x04; + + /** Start of the unsupported attributes group section. */ + public static final byte UNSUPPORTED_ATTRIBUTES_TAG = 0x05; + + + // 0x00 reserved for definition in a future IETF + // standards track document + + // 0x06-0x0f reserved for future delimiters in IETF + // standards track documents + + private IppDelimiterTag() + { + // not to be instantiated + } + + /** + * Tests if given value corresponds to a + * delimiter tag value. + * + * @param value the value to test for + * @return true if, false otherwise. + */ + public static boolean isDelimiterTag(byte value) + { + if (value >= 0x01 && value <= 0x05) + return true; + + return false; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/IppException.java b/libjava/classpath/gnu/javax/print/ipp/IppException.java new file mode 100644 index 000000000..c34a8f227 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/IppException.java @@ -0,0 +1,88 @@ +/* IppException.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp; + +import javax.print.PrintException; + +/** + * IppException signals exception thrown by + * the IPP implementation for various things like a failed + * ipp request or a wrapped io exception. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public class IppException extends PrintException +{ + /** + * Creates an IppException. + */ + public IppException() + { + super(); + } + + /** + * Creates an IppException. + * @param s the message of the exception. + */ + public IppException(String s) + { + super(s); + } + + /** + * Creates an IppException. + * @param e the exception cause this one. + */ + public IppException(Exception e) + { + super(e); + } + + /** + * Creates an IppException. + * @param s the message of the exception. + * @param e the exception cause this one. + */ + public IppException(String s, Exception e) + { + super(s, e); + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/IppMultiDocPrintService.java b/libjava/classpath/gnu/javax/print/ipp/IppMultiDocPrintService.java new file mode 100644 index 000000000..59c3408d5 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/IppMultiDocPrintService.java @@ -0,0 +1,87 @@ +/* IppMultiDocPrintService.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp; + + +import java.net.URI; + +import javax.print.MultiDocPrintJob; +import javax.print.MultiDocPrintService; + +/** + * Implementation of the MultiDocPrintService interface + * for IPP based printers. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public class IppMultiDocPrintService extends IppPrintService + implements MultiDocPrintService +{ + /** The username. */ + private transient String user; + + /** The password of the user. */ + private transient String passwd; + + /** + * Creates a IppMultiDocPrintService object. + * + * @param uri the URI of the IPP printer. + * @param username the user of this print service. + * @param password the password of the user. + * + * @throws IppException if an error during connection occurs. + */ + public IppMultiDocPrintService(URI uri, String username, String password) + throws IppException + { + super(uri, username, password); + user = username; + passwd = password; + } + + /** + * @see MultiDocPrintService#createMultiDocPrintJob() + */ + public MultiDocPrintJob createMultiDocPrintJob() + { + return new MultiDocPrintJobImpl(this, user, passwd); + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/IppPrintService.java b/libjava/classpath/gnu/javax/print/ipp/IppPrintService.java new file mode 100644 index 000000000..9ce41c774 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/IppPrintService.java @@ -0,0 +1,924 @@ +/* IppPrintService.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp; + +import gnu.classpath.SystemProperties; +import gnu.classpath.debug.Component; +import gnu.classpath.debug.SystemLogger; +import gnu.javax.print.ipp.attribute.DefaultValueAttribute; +import gnu.javax.print.ipp.attribute.RequestedAttributes; +import gnu.javax.print.ipp.attribute.defaults.CopiesDefault; +import gnu.javax.print.ipp.attribute.defaults.FinishingsDefault; +import gnu.javax.print.ipp.attribute.defaults.JobHoldUntilDefault; +import gnu.javax.print.ipp.attribute.defaults.JobPriorityDefault; +import gnu.javax.print.ipp.attribute.defaults.JobSheetsDefault; +import gnu.javax.print.ipp.attribute.defaults.MediaDefault; +import gnu.javax.print.ipp.attribute.defaults.MultipleDocumentHandlingDefault; +import gnu.javax.print.ipp.attribute.defaults.NumberUpDefault; +import gnu.javax.print.ipp.attribute.defaults.OrientationRequestedDefault; +import gnu.javax.print.ipp.attribute.defaults.PrintQualityDefault; +import gnu.javax.print.ipp.attribute.defaults.PrinterResolutionDefault; +import gnu.javax.print.ipp.attribute.defaults.SidesDefault; +import gnu.javax.print.ipp.attribute.printer.DocumentFormat; +import gnu.javax.print.ipp.attribute.supported.CompressionSupported; +import gnu.javax.print.ipp.attribute.supported.DocumentFormatSupported; +import gnu.javax.print.ipp.attribute.supported.FinishingsSupported; +import gnu.javax.print.ipp.attribute.supported.JobHoldUntilSupported; +import gnu.javax.print.ipp.attribute.supported.JobSheetsSupported; +import gnu.javax.print.ipp.attribute.supported.MediaSupported; +import gnu.javax.print.ipp.attribute.supported.MultipleDocumentHandlingSupported; +import gnu.javax.print.ipp.attribute.supported.OperationsSupported; +import gnu.javax.print.ipp.attribute.supported.OrientationRequestedSupported; +import gnu.javax.print.ipp.attribute.supported.PageRangesSupported; +import gnu.javax.print.ipp.attribute.supported.PrintQualitySupported; +import gnu.javax.print.ipp.attribute.supported.PrinterResolutionSupported; +import gnu.javax.print.ipp.attribute.supported.PrinterUriSupported; +import gnu.javax.print.ipp.attribute.supported.SidesSupported; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.logging.Logger; + +import javax.print.DocFlavor; +import javax.print.DocPrintJob; +import javax.print.PrintService; +import javax.print.ServiceUIFactory; +import javax.print.attribute.Attribute; +import javax.print.attribute.AttributeSet; +import javax.print.attribute.AttributeSetUtilities; +import javax.print.attribute.HashAttributeSet; +import javax.print.attribute.HashPrintServiceAttributeSet; +import javax.print.attribute.IntegerSyntax; +import javax.print.attribute.PrintServiceAttribute; +import javax.print.attribute.PrintServiceAttributeSet; +import javax.print.attribute.standard.Compression; +import javax.print.attribute.standard.Copies; +import javax.print.attribute.standard.CopiesSupported; +import javax.print.attribute.standard.Fidelity; +import javax.print.attribute.standard.Finishings; +import javax.print.attribute.standard.JobHoldUntil; +import javax.print.attribute.standard.JobImpressions; +import javax.print.attribute.standard.JobImpressionsSupported; +import javax.print.attribute.standard.JobKOctets; +import javax.print.attribute.standard.JobKOctetsSupported; +import javax.print.attribute.standard.JobMediaSheets; +import javax.print.attribute.standard.JobMediaSheetsSupported; +import javax.print.attribute.standard.JobName; +import javax.print.attribute.standard.JobPriority; +import javax.print.attribute.standard.JobPrioritySupported; +import javax.print.attribute.standard.JobSheets; +import javax.print.attribute.standard.Media; +import javax.print.attribute.standard.MultipleDocumentHandling; +import javax.print.attribute.standard.NumberUp; +import javax.print.attribute.standard.NumberUpSupported; +import javax.print.attribute.standard.OrientationRequested; +import javax.print.attribute.standard.PageRanges; +import javax.print.attribute.standard.PrintQuality; +import javax.print.attribute.standard.PrinterName; +import javax.print.attribute.standard.PrinterResolution; +import javax.print.attribute.standard.PrinterURI; +import javax.print.attribute.standard.RequestingUserName; +import javax.print.attribute.standard.Sides; +import javax.print.event.PrintServiceAttributeListener; + + +/** + * Implementation of the PrintService interface + * for IPP based printers. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public class IppPrintService implements PrintService +{ + /** + * A Map with sets of attributes. + * key: A attribute category + * value: A set with values + * + * IPP may return sets of attributes e.g. for supported + * compression methods so we need to map to sets here. + */ + private Map, Set> printerAttr; + + /** The set of listeners.*/ + private HashSet printServiceAttributeListener; + + /** The username. */ + private transient String user; + + /** The password of the user. */ + private transient String passwd; + + /** The name of this print service. */ + private String name; + + /** The list of supported document flavors. */ + private List flavors; + + /** The standard printer URI. */ + private PrinterURI printerUri; + + /** The list of all supported printer URIs. */ + private ArrayList printerUris; + + /** + * Logger for tracing - enable by passing + * -Dgnu.classpath.debug.components=ipp to the vm. + */ + static final Logger logger = SystemLogger.SYSTEM; + + /** + * requesting-user-name defaults to the executing user. + */ + public static final RequestingUserName REQUESTING_USER_NAME; + + /** + * job-name defaults to "Java Printing". + */ + public static final JobName JOB_NAME; + + static + { + JOB_NAME = new JobName("Java Printing", null); + REQUESTING_USER_NAME = new RequestingUserName( + SystemProperties.getProperty("user.name", ""), null); + } + + // TODO Implement service listener notification and change detection. + + /** + * Creates a IppPrintService object. + * + * @param uri the URI of the IPP printer. + * @param username the user of this print service. + * @param password the password of the user. + * + * @throws IppException if an error during connection occurs. + */ + public IppPrintService(URI uri, String username, String password) + throws IppException + { + printerUri = new PrinterURI(uri); + user = username; + passwd = password; + + printServiceAttributeListener = + new HashSet(); + + printerAttr = getPrinterAttributes(); + processResponse(); + } + + /** + * Fetches all printer attributes from the IPP printer. + * + * @return The Map with the printer attributes. + * @throws IppException if an error occurs. + */ + private Map, Set> getPrinterAttributes() + throws IppException + { + IppResponse response = null; + + try + { + IppRequest request = new IppRequest(printerUri.getURI(), user, passwd); + + int operation = OperationsSupported.GET_PRINTER_ATTRIBUTES.getValue(); + request.setOperationID((short) operation); + request.setOperationAttributeDefaults(); + request.addOperationAttribute(printerUri); + + response = request.send(); + } + catch (IOException e) + { + throw new IppException("IOException in IPP request/response.", e); + } + + return response.getPrinterAttributes().get(0); + } + + /** + * Extracts the set of attribute values for a given + * attribute category from the printer attributes map. + * + * @param attributeClass the category + * @return The set of attributes of the category. + */ + private Set getPrinterAttributeSet(Class attributeClass) + { + Set set = printerAttr.get(attributeClass); + Set attSet = new HashSet(); + for (Attribute att : set) + attSet.add(attributeClass.cast(att)); + return attSet; + } + + /** + * Extracts the default attribute value for the given + * default attribute category from the printer attributes map. + * + * @param attributeClass the category + * @return The default attribute. + * + * @throws ClassCastException if attributClass is not an + * instance of DefaultValueAttribute. + */ + private Attribute getPrinterDefaultAttribute(Class attributeClass) + { + Set set = printerAttr.get(attributeClass); + return ((DefaultValueAttribute) set.toArray()[0]).getAssociatedAttribute(); + } + + /** + * Processes the response, sorts and splits the attributes. + */ + private void processResponse() + { + // printer name + PrinterName[] tmp = getPrinterAttributeSet(PrinterName.class).toArray(new PrinterName[1]); + name = tmp[0].getValue(); + + // supported flavors + // TODO Check if charsets-supported are charsets that are actually supported + // for text doc flavors as cups doesn't send charset parameters + + // utf-8 is supported at least - so we go with this only for now + flavors = new ArrayList(); + Set flavorAttributes = getPrinterAttributeSet(DocumentFormatSupported.class); + if (flavorAttributes != null) + { + for (DocumentFormatSupported dfs : flavorAttributes) + { + String mimeType = dfs.getValue(); + + if (mimeType.equals("text/plain")) + { + flavors.add(DocFlavor.CHAR_ARRAY.TEXT_PLAIN); + flavors.add(DocFlavor.READER.TEXT_PLAIN); + flavors.add(DocFlavor.STRING.TEXT_PLAIN); + + // add utf-8 + mimeType = mimeType + "; charset=utf-8"; + } + else if (mimeType.equals("text/html")) + { + flavors.add(DocFlavor.CHAR_ARRAY.TEXT_HTML); + flavors.add(DocFlavor.READER.TEXT_HTML); + flavors.add(DocFlavor.STRING.TEXT_HTML); + + // add utf-8 + mimeType = mimeType + "; charset=utf-8"; + } + + // Process the predefined DocFlavors and if mimetype is + // equal put them into the flavors array - otherwise + // just build them as binarie class representation. + boolean changed = false; + try + { + Class[] clazzes = new Class[] { DocFlavor.BYTE_ARRAY.class, + DocFlavor.INPUT_STREAM.class, + DocFlavor.URL.class + }; + + for (int j = 0; j < clazzes.length; j++) + { + Field[] fields = clazzes[j].getDeclaredFields(); + for (int i = 0; i < fields.length; i++) + { + if (fields[i].getType().equals(clazzes[j])) + { + DocFlavor flavor = (DocFlavor) fields[i].get(null); + if (flavor.getMimeType().equals(mimeType)) + changed = flavors.add(flavor); + } + } + } + if (!changed) // not in predefined constants of DocFlavor + { + // everything should be supported as binary stuff + flavors.add(new DocFlavor(mimeType, "[B")); + flavors.add(new DocFlavor(mimeType, "java.io.InputStream")); + flavors.add(new DocFlavor(mimeType, "java.net.URL")); + } + } + catch (SecurityException e) + { + // should not happen + } + catch (IllegalArgumentException e) + { + // should not happen + } + catch (IllegalAccessException e) + { + // should not happen, all fields are public + } + } + + if (this.getClass() + .isAssignableFrom(gnu.javax.print.CupsPrintService.class)) + { +// CUPS always provides filters to convert from Postscript. +// This logic looks odd, but it's what OpenJDK does. + flavors.add(DocFlavor.SERVICE_FORMATTED.PAGEABLE); + flavors.add(DocFlavor.SERVICE_FORMATTED.PRINTABLE); + } + } + + // printer uris + Set uris = getPrinterAttributeSet(PrinterUriSupported.class); + printerUris = new ArrayList(uris.size()); + for (PrinterUriSupported uri : uris) + { + printerUris.add( new PrinterURI(uri.getURI())); + } + } + + /** + * We always return a implementation implementing CancelablePrintJob. + * + * @see javax.print.PrintService#createPrintJob() + */ + public DocPrintJob createPrintJob() + { + return new DocPrintJobImpl(this, user, passwd); + } + + + /** + * @see javax.print.PrintService#getAttribute(java.lang.Class) + */ + public T getAttribute(Class category) + { + if (category == null) + throw new NullPointerException("category may not be null"); + + if (! PrintServiceAttribute.class.isAssignableFrom(category)) + throw new IllegalArgumentException( + "category must be of type PrintServiceAttribute"); + + Set set = getPrinterAttributeSet(category); + if (set != null && set.size() > 0) + return set.iterator().next(); + + return null; + } + + /** + * @see javax.print.PrintService#getAttributes() + */ + public PrintServiceAttributeSet getAttributes() + { + PrintServiceAttributeSet set = new HashPrintServiceAttributeSet(); + + for (Set attrSet : printerAttr.values()) + { + for (Attribute attr : attrSet) + { + if (attr instanceof PrintServiceAttribute) + set.add(attr); + } + } + + return AttributeSetUtilities.unmodifiableView(set); + } + + /** + * @see javax.print.PrintService#getDefaultAttributeValue(java.lang.Class) + */ + public Object getDefaultAttributeValue(Class category) + { + // required attributes + if (category.equals(Fidelity.class)) + return Fidelity.FIDELITY_FALSE; + if (category.equals(JobName.class)) + return JOB_NAME; + if (category.equals(RequestingUserName.class)) + return REQUESTING_USER_NAME; + + // optional attributes + if (category.equals(JobPriority.class) + && printerAttr.containsKey(JobPriorityDefault.class)) + return getPrinterDefaultAttribute(JobPriorityDefault.class); + if (category.equals(JobHoldUntil.class) + && printerAttr.containsKey(JobHoldUntilDefault.class)) + return getPrinterDefaultAttribute(JobHoldUntilDefault.class); + if (category.equals(JobSheets.class) + && printerAttr.containsKey(JobSheetsDefault.class)) + return getPrinterDefaultAttribute(JobSheetsDefault .class); + if (category.equals(MultipleDocumentHandling.class) + && printerAttr.containsKey(MultipleDocumentHandlingDefault.class)) + return getPrinterDefaultAttribute(MultipleDocumentHandlingDefault.class); + if (category.equals(Copies.class) + && printerAttr.containsKey(CopiesDefault.class)) + return getPrinterDefaultAttribute(CopiesDefault.class); + if (category.equals(Finishings.class) + && printerAttr.containsKey(FinishingsDefault.class)) + return getPrinterDefaultAttribute(FinishingsDefault.class); + if (category.equals(Sides.class) + && printerAttr.containsKey(SidesDefault.class)) + return getPrinterDefaultAttribute(SidesDefault.class); + if (category.equals(NumberUp.class) + && printerAttr.containsKey(NumberUpDefault.class)) + return getPrinterDefaultAttribute(NumberUpDefault.class); + if (category.equals(OrientationRequested.class) + && printerAttr.containsKey(OrientationRequestedDefault.class)) + return getPrinterDefaultAttribute(OrientationRequestedDefault.class); + if (category.equals(Media.class) + && printerAttr.containsKey(MediaDefault.class)) + return getPrinterDefaultAttribute(MediaDefault.class); + if (category.equals(PrinterResolution.class) + && printerAttr.containsKey(PrinterResolutionDefault.class)) + return getPrinterDefaultAttribute(PrinterResolutionDefault.class); + if (category.equals(PrintQuality.class) + && printerAttr.containsKey(PrintQualityDefault.class)) + return getPrinterDefaultAttribute(PrintQualityDefault.class); + if (category.equals(Compression.class) + && printerAttr.containsKey(CompressionSupported.class)) + return Compression.NONE; + if (category.equals(PageRanges.class)) + return new PageRanges(1, Integer.MAX_VALUE); + + return null; + } + + /** + * We return the value of PrinterName here. + * @see javax.print.PrintService#getName() + */ + public String getName() + { + return name; + } + + /** + * We currently provide no factories - just returns null. + * @see javax.print.PrintService#getServiceUIFactory() + */ + public ServiceUIFactory getServiceUIFactory() + { + // SUN does not provide any service factory for + // print services (tested on linux/windows) + + // for the moment we do the same - just return null + // later on we could provide at least the about UI dialog + return null; + } + + /** + * @see javax.print.PrintService#getSupportedAttributeCategories() + */ + public Class[] getSupportedAttributeCategories() + { + Set> categories = + new HashSet>(); + + // Should only be job template attributes as of section 4.2 + if (printerAttr.containsKey(JobPrioritySupported.class)) + categories.add(JobPriority.class); + if (printerAttr.containsKey(JobHoldUntilSupported.class)) + categories.add(JobHoldUntil.class); + if (printerAttr.containsKey(JobSheetsSupported.class)) + categories.add(JobSheets.class); + if (printerAttr.containsKey(MultipleDocumentHandlingSupported.class)) + categories.add(MultipleDocumentHandling.class); + if (printerAttr.containsKey(CopiesSupported.class)) + categories.add(Copies.class); + if (printerAttr.containsKey(FinishingsSupported.class)) + { + // if only none finishing is supported - it does not count as supported + Set set = getPrinterAttributeSet(FinishingsSupported.class); + if (! (set.size() == 1 && set.contains(FinishingsSupported.NONE))) + categories.add(Finishings.class); + } + if (printerAttr.containsKey(PageRangesSupported.class)) + categories.add(PageRanges.class); + if (printerAttr.containsKey(SidesSupported.class)) + categories.add(Sides.class); + if (printerAttr.containsKey(NumberUpSupported.class)) + categories.add(NumberUp.class); + if (printerAttr.containsKey(OrientationRequestedSupported.class)) + categories.add(OrientationRequested.class); + if (printerAttr.containsKey(MediaSupported.class)) + categories.add(Media.class); + if (printerAttr.containsKey(PrinterResolutionSupported.class)) + categories.add(PrinterResolution.class); + if (printerAttr.containsKey(PrintQualitySupported.class)) + categories.add(PrintQuality.class); + + // Chromaticity, Destination, MediaPrintableArea, + // SheetCollate, PresentationDirection - not IPP attributes + + // attributes outside section 4.2 + if (printerAttr.containsKey(CompressionSupported.class)) + categories.add(Compression.class); + if (printerAttr.containsKey(JobImpressionsSupported.class)) + categories.add(JobImpressions.class); + if (printerAttr.containsKey(JobKOctetsSupported.class)) + categories.add(JobKOctets.class); + if (printerAttr.containsKey(JobMediaSheetsSupported.class)) + categories.add(JobMediaSheets.class); + + // always supported as required by IPP specification + categories.add(Fidelity.class); + categories.add(JobName.class); + categories.add(RequestingUserName.class); + + return categories.toArray(new Class[categories.size()]); + } + + /** + * Implemented by a GetPrinterAttributes request. Subclasses providing supported + * attribute values totally different may override this methods. Subclass only in + * need of handling the response differently may override the method + * handleSupportedAttributeValuesResponse(IppResponse, Class) only. + * + * @see PrintService#getSupportedAttributeValues(Class, DocFlavor, AttributeSet) + * @see #handleSupportedAttributeValuesResponse(IppResponse, Class) + */ + public Object getSupportedAttributeValues(Class category, + DocFlavor flavor, AttributeSet attributes) + { + // We currently ignore the attribute set - there is nothing in the IPP + // specification which would come closer to what we do here. + + if (category == null) + throw new NullPointerException("category may not be null"); + + if (!Attribute.class.isAssignableFrom(category)) + throw new IllegalArgumentException("category must be of type Attribute"); + + if (flavor != null && !isDocFlavorSupported(flavor)) + throw new IllegalArgumentException("flavor is not supported"); + + if (!isAttributeCategorySupported(category)) + return null; + + // always supported + if (category.equals(Fidelity.class)) + return new Fidelity[] { Fidelity.FIDELITY_FALSE, Fidelity.FIDELITY_TRUE }; + if (category.equals(JobName.class)) + return JOB_NAME; + if (category.equals(RequestingUserName.class)) + return REQUESTING_USER_NAME; + + // map category to category-supported + String categoryName = IppUtilities.getSupportedAttrName(category); + + IppResponse response = null; + try + { + IppRequest request = new IppRequest(printerUri.getURI(), user, passwd); + request.setOperationID( + (short) OperationsSupported.GET_PRINTER_ATTRIBUTES.getValue()); + request.setOperationAttributeDefaults(); + request.addOperationAttribute(new RequestedAttributes(categoryName)); + request.addOperationAttribute(printerUri); + + if (flavor != null) + { + DocumentFormat f = DocumentFormat.createDocumentFormat(flavor); + request.addOperationAttribute(f); + } + + response = request.send(); + + int status = response.getStatusCode(); + if (! (status == IppStatusCode.SUCCESSFUL_OK + || status == IppStatusCode.SUCCESSFUL_OK_IGNORED_OR_SUBSTITUED_ATTRIBUTES + || status == IppStatusCode.SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES) ) + { + logger.log(Component.IPP, "Statuscode not OK - got:" + status); + } + } + catch (IOException e) + { + // method cannot throw exception - just log + logger.log(Component.IPP, "IOException", e); + } + catch (IppException e) + { + // method cannot throw exception - just log + logger.log(Component.IPP, "IPPException", e); + } + + return handleSupportedAttributeValuesResponse(response, category); + } + + /** + * Called to handle the supported attribute values response for the given + * category. This might be overridden by subclasses with different requirements + * for parsing/handling the response from the GetPrinterAttributes. + * + * @param response the response of the GetPrinterAttributes IPP request + * @param category the category for which the supported values are requested + * @return A object indicating the supported values for the given attribute + * category, or null if this print service doesn't support the + * given attribute category at all. + * + * @see #getSupportedAttributeValues(Class, DocFlavor, AttributeSet) + */ + protected Object handleSupportedAttributeValuesResponse(IppResponse response, + Class category) + { + List, Set>> printerAtts = + response.getPrinterAttributes(); + + // only one will be returned + Map, Set> printerAttribute = printerAtts.get(0); + Class suppCategory = IppUtilities.getSupportedCategory(category); + Set attr = printerAttribute.get(suppCategory); + + // We sometime assume its a single instance with arbritrary value just indicating + // support or an array which is returned. This is because I sometimes just choosed + // what sounds right to me - as I have yet to find a printer which supports every + // special category in the SUN implementation to see what they return :-) + + // Map whats in the JSP API + if (suppCategory.equals(JobPrioritySupported.class)) + return (JobPrioritySupported) attr.iterator().next(); + if (suppCategory.equals(JobHoldUntilSupported.class)) + return new JobHoldUntil(new Date()); + if (suppCategory.equals(JobSheetsSupported.class)) + return JobSheetsSupported.getAssociatedAttributeArray(attr); + if (suppCategory.equals(MultipleDocumentHandlingSupported.class)) + return MultipleDocumentHandlingSupported.getAssociatedAttributeArray(attr); + if (suppCategory.equals(CopiesSupported.class)) + return (CopiesSupported) attr.iterator().next(); + if (suppCategory.equals(FinishingsSupported.class)) + return FinishingsSupported.getAssociatedAttributeArray(attr); + if (suppCategory.equals(PageRangesSupported.class)) + return new PageRanges[] { new PageRanges(1, Integer.MAX_VALUE) }; + if (suppCategory.equals(OrientationRequestedSupported.class)) + return OrientationRequestedSupported.getAssociatedAttributeArray(attr); + if (suppCategory.equals(MediaSupported.class)) + return MediaSupported.getAssociatedAttributeArray(attr); + if (suppCategory.equals(PrinterResolutionSupported.class)) + return PrinterResolutionSupported.getAssociatedAttributeArray(attr); + if (suppCategory.equals(PrintQualitySupported.class)) + return PrintQualitySupported.getAssociatedAttributeArray(attr); + if (suppCategory.equals(CompressionSupported.class)) + return CompressionSupported.getAssociatedAttributeArray(attr); + // Special handling as it might also be in range of integers + if (suppCategory.equals(NumberUpSupported.class)) + { + if (attr.size() == 1) // number-up maybe in rangeofintegers + return attr.iterator().next(); + + int[][] members = new int[attr.size()][2]; + Iterator it = attr.iterator(); + for (int j = 0; j < attr.size(); j++) + { + int value = ((NumberUpSupported) it.next()).getMembers()[0][0]; + members[j] = new int[] { value, value }; + } + + NumberUpSupported supported = new NumberUpSupported(members); + return supported; + } + + return null; + } + + /** + * @see javax.print.PrintService#getSupportedDocFlavors() + */ + public DocFlavor[] getSupportedDocFlavors() + { + return flavors.toArray(new DocFlavor[flavors.size()]); + } + + /** + * This is done by a validate-job operation and actually implemented in + * this generic IPP reference implementation. Subclasses which does + * not correctly support Validate-Job operation might want to override this. + * + * @see PrintService#getUnsupportedAttributes(DocFlavor, AttributeSet) + */ + public AttributeSet getUnsupportedAttributes(DocFlavor flavor, + AttributeSet attributes) + { + if (flavor != null && !isDocFlavorSupported(flavor)) + throw new IllegalArgumentException("flavor is not supported"); + + IppResponse response = null; + try + { + IppRequest request = new IppRequest(printerUri.getURI(), user, passwd); + short operationId = (short) OperationsSupported.VALIDATE_JOB.getValue(); + request.setOperationID(operationId); + request.setOperationAttributeDefaults(); + request.addOperationAttribute(printerUri); + request.addOperationAttribute(Fidelity.FIDELITY_TRUE); + + if (attributes != null && attributes.size() > 0) + { + request.addAndFilterJobOperationAttributes(attributes); + request.addAndFilterJobTemplateAttributes(attributes); + } + + if (flavor != null) + { + DocumentFormat f = DocumentFormat.createDocumentFormat(flavor); + request.addOperationAttribute(f); + } + + response = request.send(); + + int status = response.getStatusCode(); + if (! (status == IppStatusCode.SUCCESSFUL_OK + || status == IppStatusCode.SUCCESSFUL_OK_IGNORED_OR_SUBSTITUED_ATTRIBUTES + || status == IppStatusCode.SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES) ) + { + logger.log(Component.IPP, "Statuscode not OK - got:" + status); + } + } + catch (IOException e) + { + // method cannot throw exception - just log + logger.log(Component.IPP, "IOException", e); + } + catch (IppException e) + { + // method cannot throw exception - just log + logger.log(Component.IPP, "IPPException", e); + } + + // Validate Jobs returns only Unsupported and Operation + List, Set>> unsupportedMaps = + response.getUnsupportedAttributes(); + if (unsupportedMaps.size() == 0) + return null; + + Map, Set> unsupportedAttr = unsupportedMaps.get(0); + if (unsupportedAttr.size() == 0) + return null; + + // Convert the return map with unsupported attributes + // into an AttribueSet instance + HashAttributeSet set = new HashAttributeSet(); + for (Set unsupported : unsupportedAttr.values()) + { + for (Attribute att : unsupported) + set.add(att); + } + + return set; + } + + /** + * @see PrintService#isAttributeCategorySupported(Class) + */ + public boolean isAttributeCategorySupported(Class category) + { + if (category == null) + throw new NullPointerException("category may not be null"); + + if (! Attribute.class.isAssignableFrom(category)) + throw new IllegalArgumentException("category must be of type Attribute"); + + return Arrays.asList(getSupportedAttributeCategories()).contains(category); + } + + /** + * @see PrintService#isAttributeValueSupported(Attribute, DocFlavor, AttributeSet) + */ + public boolean isAttributeValueSupported(Attribute attrval, DocFlavor flavor, + AttributeSet attributes) + { + // just redirect to getSupportedAttributeValues + Object values = getSupportedAttributeValues(attrval.getCategory(), + flavor, attributes); + // null means none supported + if (values == null) + return false; + + // object may be an array + if (values.getClass().isArray()) + return Arrays.asList((Object[]) values).contains(attrval); + + // may be a single instance of the category (value is irrelevant) + if (values.getClass().equals(attrval.getCategory())) + return true; + + // a single instance of another class to give the bounds + // copies + if (values.getClass().equals(CopiesSupported.class)) + return ((CopiesSupported) values).contains((IntegerSyntax) attrval); + // number up + if (values.getClass().equals(NumberUpSupported.class)) + return ((NumberUpSupported) values).contains((IntegerSyntax) attrval); + // job priority + if (values.getClass().equals(JobPrioritySupported.class)) + { + JobPriority priority = (JobPriority) attrval; + JobPrioritySupported maxSupported = (JobPrioritySupported) values; + if (priority.getValue() < maxSupported.getValue()) + return true; + } + + // I am unsure if these might also show up - not yet found a printer where + // Suns implementation supports them: + // JobImpressionsSupported, JobKOctetsSupported, JobMediaSheetsSupported + + return false; + } + + + /** + * @see javax.print.PrintService#isDocFlavorSupported(DocFlavor) + */ + public boolean isDocFlavorSupported(DocFlavor flavor) + { + if (flavor == null) + throw new NullPointerException("DocFlavor may not be null."); + + return flavors.contains(flavor); + } + + + /** + * @see PrintService#addPrintServiceAttributeListener(PrintServiceAttributeListener) + */ + public void addPrintServiceAttributeListener( + PrintServiceAttributeListener listener) + { + printServiceAttributeListener.add(listener); + } + + /** + * @see PrintService#removePrintServiceAttributeListener(PrintServiceAttributeListener) + */ + public void removePrintServiceAttributeListener( + PrintServiceAttributeListener listener) + { + printServiceAttributeListener.remove(listener); + } + + /** + * Returns "IppPrinter: " + getName() + * @return The string representation. + */ + public String toString() + { + return "IppPrinter: " + getName(); + } + + /** + * Returns the printer-uri of this print service. + * + * @return The printer-uri attribute. + */ + public PrinterURI getPrinterURI() + { + return printerUri; + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/IppRequest.java b/libjava/classpath/gnu/javax/print/ipp/IppRequest.java new file mode 100644 index 000000000..ae1f2c409 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/IppRequest.java @@ -0,0 +1,875 @@ +/* IppRequest.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., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.javax.print.ipp; + +import gnu.classpath.debug.Component; +import gnu.classpath.debug.SystemLogger; +import gnu.javax.print.ipp.attribute.CharsetSyntax; +import gnu.javax.print.ipp.attribute.NaturalLanguageSyntax; +import gnu.javax.print.ipp.attribute.RequestedAttributes; +import gnu.javax.print.ipp.attribute.job.AttributesCharset; +import gnu.javax.print.ipp.attribute.job.AttributesNaturalLanguage; +import gnu.javax.print.ipp.attribute.job.JobId; +import gnu.javax.print.ipp.attribute.job.JobUri; +import gnu.javax.print.ipp.attribute.printer.DocumentFormat; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URL; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.List; +import java.util.logging.Logger; + +import javax.print.attribute.Attribute; +import javax.print.attribute.AttributeSet; +import javax.print.attribute.DateTimeSyntax; +import javax.print.attribute.EnumSyntax; +import javax.print.attribute.HashAttributeSet; +import javax.print.attribute.IntegerSyntax; +import javax.print.attribute.ResolutionSyntax; +import javax.print.attribute.SetOfIntegerSyntax; +import javax.print.attribute.TextSyntax; +import javax.print.attribute.URISyntax; +import javax.print.attribute.standard.Compression; +import javax.print.attribute.standard.Copies; +import javax.print.attribute.standard.DocumentName; +import javax.print.attribute.standard.Fidelity; +import javax.print.attribute.standard.Finishings; +import javax.print.attribute.standard.JobHoldUntil; +import javax.print.attribute.standard.JobImpressions; +import javax.print.attribute.standard.JobKOctets; +import javax.print.attribute.standard.JobMediaSheets; +import javax.print.attribute.standard.JobName; +import javax.print.attribute.standard.JobOriginatingUserName; +import javax.print.attribute.standard.JobPriority; +import javax.print.attribute.standard.JobSheets; +import javax.print.attribute.standard.Media; +import javax.print.attribute.standard.MultipleDocumentHandling; +import javax.print.attribute.standard.NumberUp; +import javax.print.attribute.standard.OrientationRequested; +import javax.print.attribute.standard.PageRanges; +import javax.print.attribute.standard.PrintQuality; +import javax.print.attribute.standard.PrinterResolution; +import javax.print.attribute.standard.PrinterURI; +import javax.print.attribute.standard.RequestingUserName; +import javax.print.attribute.standard.SheetCollate; +import javax.print.attribute.standard.Sides; + +/** + * IppRequest models a request to an IPP compatible + * server as described in RFC 2910 - IPP/1.1: Encoding and Transport. + *

    + * The byte stream is structured as follows (for an official description + * please have a look at the RFC document mentioned above): + *

      + *
    • version-number - 2 bytes - required
    • + *
    • operation-id - 2 bytes - required
    • + *
    • request-id - 4 bytes - required
    • + *
    • attribute-group - n bytes - 0 or more
    • + *
    • end-of-attributes-tag - 1 byte - required
    • + *
    • data - q bytes - optional
    • + *
    + *

    + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public class IppRequest +{ + + /** + * The printer-poll timeout. + */ + private static final int timeout = 1000; + + /** + * Helper class used to write the attributes of a request + * into the supplied data output stream in the correct way. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ + class RequestWriter + { + private DataOutputStream out; + + /** + * Creates a RequestWriter. + * + * @param stream the stream to write to. + */ + RequestWriter(DataOutputStream stream) + { + out = stream; + } + + /** + * Writes an attribute in IntegerSyntax into the stream. + * @param attribute the attribute + * @throws IOException if thrown by the stream + */ + private void write(IntegerSyntax attribute) throws IOException + { + String name = ((Attribute) attribute).getName(); + out.writeByte(IppValueTag.INTEGER); + out.writeShort(name.length()); + out.write(name.getBytes()); + out.writeShort(4); // length, integer is 4 bytes + out.writeInt(attribute.getValue()); + } + + /** + * Writes an attribute in EnumSyntax into the stream. + * @param attribute the attribute + * @throws IOException if thrown by the stream + */ + private void write(EnumSyntax attribute) throws IOException + { + // in JPS API enum syntax is used for enums, keyword and boolean types + String name = ((Attribute) attribute).getName(); + + // the enum value types + if (attribute instanceof Finishings + || attribute instanceof OrientationRequested + || attribute instanceof PrintQuality) + { + out.writeByte(IppValueTag.ENUM); + out.writeShort(name.length()); + out.write(name.getBytes()); + out.writeShort(4); // length, enum is 4 bytes + out.writeInt(attribute.getValue()); + } + // the boolean value type + else if (attribute instanceof Fidelity) + { + out.writeByte(IppValueTag.BOOLEAN); + out.writeShort(name.length()); + out.write(name.getBytes()); + out.writeShort(1); // length, boolean is 1 bytes + out.writeByte(attribute.getValue() == 0 ? 0x00 : 0x01); + } + // the keyword value types + else + { + String keyword = attribute.toString(); + out.writeByte(IppValueTag.KEYWORD); + out.writeShort(name.length()); + out.write(name.getBytes()); + out.writeShort(keyword.length()); + out.write(keyword.getBytes()); + } + } + + /** + * Writes an attribute in SetOfIntegerSyntax into the stream. + * @param attribute the attribute + * @throws IOException if thrown by the stream + */ + private void write(SetOfIntegerSyntax attribute) throws IOException + { + String name = ((Attribute) attribute).getName(); + int[][] ranges = attribute.getMembers(); + for (int i = 0; i < ranges.length; i++) + { + out.writeByte(IppValueTag.RANGEOFINTEGER); + if (i == 0) + { + out.writeShort(name.length()); + out.write(name.getBytes()); + } + else + out.writeShort(0x0000); // only name-length + + out.writeShort(8); // range is 8 bytes + out.writeInt(ranges[i][0]); + out.writeInt(ranges[i][1]); + } + } + + /** + * Writes an attribute in ResolutionSyntax into the stream. + * @param attribute the attribute + * @throws IOException if thrown by the stream + */ + private void write(ResolutionSyntax attribute) throws IOException + { + String name = ((Attribute) attribute).getName(); + out.writeByte(IppValueTag.RESOLUTION); + out.writeShort(name.length()); + out.write(name.getBytes()); + out.writeShort(9); // length fixed to 9 + out.writeInt(attribute.getCrossFeedResolution(ResolutionSyntax.DPI)); + out.writeInt(attribute.getFeedResolution(ResolutionSyntax.DPI)); + out.writeByte(ResolutionSyntax.DPI); + } + + /** + * Writes an attribute in DateTimeSyntax into the stream. + *

    + * The syntax value is defined as 11 octets follwing the + * DateAndTime format of RFC 1903. (see IppResponse) + *

    + * + * @param attribute the attribute + * @throws IOException if thrown by the stream + */ + private void write(DateTimeSyntax attribute) throws IOException + { + String name = ((Attribute) attribute).getName(); + out.writeByte(IppValueTag.DATETIME); + out.writeShort(name.length()); + out.write(name.getBytes()); + out.writeShort(11); // length fixed to 11 + + Date date = attribute.getValue(); + Calendar cal = new GregorianCalendar(); + cal.setTime(date); + + out.writeShort(cal.get(Calendar.YEAR)); + out.writeByte(cal.get(Calendar.MONTH)); + out.writeByte(cal.get(Calendar.DAY_OF_MONTH)); + out.writeByte(cal.get(Calendar.HOUR_OF_DAY)); + out.writeByte(cal.get(Calendar.MINUTE)); + int second = cal.get(Calendar.SECOND); + out.writeByte(second == 0 ? 60 : second); + out.writeByte(cal.get(Calendar.MILLISECOND) / 100); + + int offsetInMillis = cal.get(Calendar.ZONE_OFFSET); + char directionFromUTC = '+'; + if (offsetInMillis < 0) + { + directionFromUTC = '-'; + offsetInMillis = offsetInMillis * (-1); + } + + out.writeByte(directionFromUTC); + out.writeByte(offsetInMillis / 3600000); // hours + out.writeByte((offsetInMillis % 3600000) / 60000); // minutes + } + + /** + * Writes an attribute in TextSyntax into the stream. + *

    + * By default attributes are qritten as TEXT_WITHOUT_LANGUAGE value-tag. + * As some attributes in the JPS are TextSyntax attributes but actually + * of NAME value-tag in IPP this method checks for these attributes and + * writes them as NAME_WITHOUT_LANGUAGE value-tag into the stream. + *

    + * + * @param attribute the attribute + * @param out the stream to write to + * @throws IOException if thrown by the stream + */ + private void write(TextSyntax attribute) throws IOException + { + // We only use *WithoutLanguage, correct according to spec. + String name = ((Attribute) attribute).getName(); + + if (attribute instanceof RequestingUserName + || attribute instanceof JobName + || attribute instanceof DocumentName + || attribute instanceof JobOriginatingUserName) + out.writeByte(IppValueTag.NAME_WITHOUT_LANGUAGE); + else if (attribute instanceof DocumentFormat) + out.writeByte(IppValueTag.MIME_MEDIA_TYPE); + else + out.writeByte(IppValueTag.TEXT_WITHOUT_LANGUAGE); + + out.writeShort(name.length()); + out.write(name.getBytes()); + out.writeShort(attribute.getValue().length()); + out.write(attribute.getValue().getBytes()); + } + + /** + * Writes an attribute in URISyntax into the stream. + * @param attribute the attribute + * @param out the stream to write to + * @throws IOException if thrown by the stream + */ + private void write(URISyntax attribute) throws IOException + { + // only uriScheme syntax type should not appear + // in a request (reference-uri-schemes-supported) + String name = ((Attribute) attribute).getName(); + String uriAscii = attribute.getURI().toASCIIString(); + out.writeByte(IppValueTag.URI); + out.writeShort(name.length()); + out.write(name.getBytes()); + out.writeShort(uriAscii.length()); + out.write(uriAscii.getBytes()); + } + + /** + * Writes an attribute in CharsetSyntax into the stream. + * @param attribute the attribute + * @param out the stream to write to + * @throws IOException if thrown by the stream + */ + private void write(CharsetSyntax attribute) throws IOException + { + String name = ((Attribute) attribute).getName(); + out.writeByte(IppValueTag.CHARSET); + out.writeShort(name.length()); + out.write(name.getBytes()); + out.writeShort(attribute.getValue().length()); + out.write(attribute.getValue().getBytes()); + } + + /** + * Writes an attribute in NaturalLanguageSyntax into the stream. + * @param attribute the attribute + * @param out the stream to write to + * @throws IOException if thrown by the stream + */ + private void write(NaturalLanguageSyntax attribute) throws IOException + { + String name = ((Attribute) attribute).getName(); + out.writeByte(IppValueTag.NATURAL_LANGUAGE); + out.writeShort(name.length()); + out.write(name.getBytes()); + out.writeShort(attribute.getValue().length()); + out.write(attribute.getValue().getBytes()); + } + + /** + * Writes an attribute in RequestedAttributes into the stream. + * @param attribute the attribute + * @param out the stream to write to + * @throws IOException if thrown by the stream + */ + private void write(RequestedAttributes attribute) throws IOException + { + String[] values = attribute.getValues(); + + String name = ((Attribute) attribute).getName(); + out.writeByte(IppValueTag.KEYWORD); + out.writeShort(name.length()); + out.write(name.getBytes()); + out.writeShort(values[0].length()); + out.write(values[0].getBytes()); + + for (int i=1; i < values.length; i++) + { + out.writeByte(IppValueTag.KEYWORD); + out.writeShort(0x0000); // length for additional value + out.writeShort(values[i].length()); + out.write(values[i].getBytes()); + } + } + + + /** + * Writes the given operation attribute group of the given map instance + * (key=group, values=set of attributes) into the supplied data + * output stream. + * + * @param attributes the set with the attributes. + * + * @throws IOException if thrown by the used DataOutputStream. + * @throws IppException if unknown attributes occur. + */ + public void writeOperationAttributes(AttributeSet attributes) + throws IOException, IppException + { + out.write(IppDelimiterTag.OPERATION_ATTRIBUTES_TAG); + + // its essential to write these two in this order and as first ones + Attribute att = attributes.get(AttributesCharset.class); + write((CharsetSyntax) att); + + logger.log(Component.IPP, "Attribute: Name: <" + + att.getCategory().getName() + "> Value: <" + att.toString() + ">"); + + attributes.remove(AttributesCharset.class); + + att = attributes.get(AttributesNaturalLanguage.class); + write((NaturalLanguageSyntax) att); + attributes.remove(AttributesNaturalLanguage.class); + + logger.log(Component.IPP, "Attribute: Name: <" + + att.getCategory().getName() + "> Value: <" + att.toString() + ">"); + + // furthermore its essential to now write out the target attribute + PrinterURI printerUri = (PrinterURI) attributes.get(PrinterURI.class); + JobUri jobUri = (JobUri) attributes.get(JobUri.class); + JobId jobId = (JobId) attributes.get(JobId.class); + RequestedAttributes reqAttrs + = (RequestedAttributes)attributes.get(RequestedAttributes.class); + if (printerUri != null && jobId == null && jobUri == null) + { + write(printerUri); + attributes.remove(PrinterURI.class); + logger.log(Component.IPP, "Attribute: Name: <" + printerUri + .getCategory().getName() + "> Value: <" + printerUri.toString() + ">"); + } + else if (jobUri != null && jobId == null && printerUri == null) + { + write(jobUri); + attributes.remove(JobUri.class); + logger.log(Component.IPP, "Attribute: Name: <" + jobUri + .getCategory().getName() + "> Value: <" + jobUri.toString() + ">"); + } + else if (printerUri != null && jobId != null && jobUri == null) + { + write(printerUri); // must be third + write(jobId); + attributes.remove(PrinterURI.class); + attributes.remove(JobId.class); + logger.log(Component.IPP, "Attribute: Name: <" + printerUri + .getCategory().getName() + "> Value: <" + printerUri.toString() + ">"); + logger.log(Component.IPP, "Attribute: Name: <" + jobId.getCategory() + .getName() + "> Value: <" + jobId.toString() + ">"); + } + else if (jobUri != null && jobId != null) + { + write(jobUri); + attributes.remove(JobUri.class); + attributes.remove(JobId.class); // MUST NOT redundant + logger.log(Component.IPP, "Attribute: Name: <" + jobUri.getCategory() + .getName() + "> Value: <" + jobUri.toString() + ">"); + } + else if (reqAttrs != null) + { + write(reqAttrs); + attributes.remove(RequestedAttributes.class); + logger.log(Component.IPP, "RequestedAttributes: <" + reqAttrs + ">"); + } + else + { + throw new IppException("Unknown target operation attribute combination."); + } + + writeAttributes(attributes); + } + + /** + * Writes the given attribute groups of the given map instance + * (key=group, values=set of attributes) into the supplied data + * output stream. + * + * @param attributes the set with the attributes. + * + * @throws IOException if thrown by the used DataOutputStream. + * @throws IppException if unknown attributes occur. + */ + public void writeAttributes(AttributeSet attributes) + throws IOException, IppException + { + Attribute[] attributeArray = attributes.toArray(); + for (int i = 0; i < attributeArray.length; i++) + { + logger.log(Component.IPP, "Attribute: Name: <" + attributeArray[i] + .getCategory().getName() + "> Value: <" + + attributeArray[i].toString() + ">"); + + if (attributeArray[i] instanceof IntegerSyntax) + write((IntegerSyntax) attributeArray[i]); + else if (attributeArray[i] instanceof TextSyntax) + write((TextSyntax) attributeArray[i]); + else if (attributeArray[i] instanceof DateTimeSyntax) + write((DateTimeSyntax) attributeArray[i]); + else if (attributeArray[i] instanceof ResolutionSyntax) + write((ResolutionSyntax) attributeArray[i]); + else if (attributeArray[i] instanceof SetOfIntegerSyntax) + write((SetOfIntegerSyntax) attributeArray[i]); + else if (attributeArray[i] instanceof EnumSyntax) + write((EnumSyntax) attributeArray[i]); + else if (attributeArray[i] instanceof URISyntax) + write((URISyntax) attributeArray[i]); + else if (attributeArray[i] instanceof CharsetSyntax) + write((CharsetSyntax) attributeArray[i]); + else if (attributeArray[i] instanceof NaturalLanguageSyntax) + write((NaturalLanguageSyntax) attributeArray[i]); + else if (attributeArray[i] instanceof RequestedAttributes) + write((RequestedAttributes) attributeArray[i]); + else + throw new IppException("Unknown syntax type"); + } + } + + } + + /** + * Logger for tracing - enable by passing + * -Dgnu.classpath.debug.components=ipp to the vm. + */ + static final Logger logger = SystemLogger.SYSTEM; + + /** + * The request id counter simply counts up + * to give unique request ids per JVM instance. + */ + private static int requestIdCounter = 1; + + /** The IPP version defaults to 1.1 */ + private static final short VERSION = 0x0101; + + /** Signals if the request is already on its way */ + private boolean alreadySent = false; + + /** The operation type of this request. */ + private short operation_id; + + /** + * The request id of this request. This is + * assigned automatically by the constructor. + */ + private final int request_id; + + private AttributeSet operationAttributes; + + private AttributeSet printerAttributes; + + private AttributeSet jobAttributes; + + private Object data; + + private URI requestUri; + + /** The underlying connection - IPP is http based */ + private HttpURLConnection connection; + + /** + * Creates an IPPRequest instance. + * + * @param uri the URI of the request + * @param user the user if any + * @param password the password of the supplied user + */ + public IppRequest(URI uri, String user, String password) + { + request_id = incrementRequestIdCounter(); + requestUri = uri; + + try + { + URL url = new URL("http", + user == null + ? uri.getHost() : user + ":" + + password + "@" + uri.getHost(), + uri.getPort(), uri.getPath()); + + connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("POST"); + connection.setDoOutput(true); + + connection.setRequestProperty("Content-type", "application/ipp"); + connection.setRequestProperty("Accept", "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2"); + } + catch (IOException e) + { + // MalformedURLException - uri is already checked + // ProtocolException - POST is correct method type + // IOException -HTTPURLConnection constructor actually + // does never throw this exception. + logger.log(Component.IPP, "Unexpected IOException", e); + } + + logger.log(Component.IPP, "[IppConnection] Host: " + uri.getHost() + + " Port: " + uri.getPort() + " Path: " + + uri.getPath()); + } + + /** + * Synchronized method to be called by the constructor + * to assign a unique request id to this request. + * + * @return The unique request id. + */ + private synchronized int incrementRequestIdCounter() + { + return IppRequest.requestIdCounter++; + } + + /** + * Returns the id of this request. + * + * @return The request ID. + */ + public int getRequestID() + { + return request_id; + } + + /** + * Sets the data of the request. The data used in this + * request will be the one of the supplied inputstream + * instead of the alternative byte array possibility. + * + * @param stream the input stream to use for the data. + */ + public void setData(InputStream stream) + { + data = stream; + } + + /** + * Sets the data of the request. The data used in this + * request will be the one of the supplied byte[] + * instead of the alternative input stream possibility. + * + * @param bytes the byte[] to use for the data. + */ + public void setData(byte[] bytes) + { + data = bytes; + } + + /** + * Sets the operation id for this request. + * + * @param id the operation id. + */ + public void setOperationID(short id) + { + operation_id = id; + } + + /** + * Adds the default values for the operation + * attributes "attributes-charset" and + * "attributes-natural-language" + */ + public void setOperationAttributeDefaults() + { + if (operationAttributes == null) + operationAttributes = new HashAttributeSet(); + + operationAttributes.add(AttributesCharset.UTF8); + operationAttributes.add(AttributesNaturalLanguage.EN); + } + + /** + * Add the job attribute of this request to the given + * attribute set. + * + * @param attribute the job attribute. + */ + public void addJobAttribute(Attribute attribute) + { + if (jobAttributes == null) + jobAttributes = new HashAttributeSet(); + + jobAttributes.add(attribute); + } + + /** + * Sets the printer attribute of this request to the given + * attribute set. + * + * @param attribute the printer attribute. + */ + public void addPrinterAttributes(Attribute attribute) + { + if (printerAttributes == null) + printerAttributes = new HashAttributeSet(); + + printerAttributes.add(attribute); + } + + /** + * Adds the given attribute to the operation attributes set. + * + * @param attribute the operation attribute to add. + */ + public void addOperationAttribute(Attribute attribute) + { + if (operationAttributes == null) + operationAttributes = new HashAttributeSet(); + + operationAttributes.add(attribute); + } + + /** + * Filters from the given attribute set the job operation out + * and adds them to the operation attributes set. + * + * @param set the attributes to filter, may not be null. + */ + public void addAndFilterJobOperationAttributes(AttributeSet set) + { + if (operationAttributes == null) + operationAttributes = new HashAttributeSet(); + + // document-natural-language - not defined in JPS attributes + // document-format - specified outside, special treatment + Attribute[] tmp = set.toArray(); + for (int i = 0; i < tmp.length; i++) + { + if (tmp[i].getCategory().equals(JobName.class) + || tmp[i].getCategory().equals(Fidelity.class) + || tmp[i].getCategory().equals(JobImpressions.class) + || tmp[i].getCategory().equals(JobKOctets.class) + || tmp[i].getCategory().equals(JobMediaSheets.class) + || tmp[i].getCategory().equals(Compression.class) + || tmp[i].getCategory().equals(DocumentName.class) + || tmp[i].getCategory().equals(RequestingUserName.class)) + + operationAttributes.add(tmp[i]); + } + } + + /** + * Filters from the given attribute set the job template attributes + * out and adds them to the job attributes set. + * + * @param set the attributes to filter, may not be null. + */ + public void addAndFilterJobTemplateAttributes(AttributeSet set) + { + if (jobAttributes == null) + jobAttributes = new HashAttributeSet(); + + // document-natural-language - not defined in JPS attributes + // document-format - specified outside, special treatment + Attribute[] tmp = set.toArray(); + for (int i = 0; i < tmp.length; i++) + { + if (tmp[i].getCategory().equals(JobPriority.class) + || tmp[i].getCategory().equals(JobHoldUntil.class) + || tmp[i].getCategory().equals(JobSheets.class) + || tmp[i].getCategory().equals(MultipleDocumentHandling.class) + || tmp[i].getCategory().equals(Copies.class) + || tmp[i].getCategory().equals(Finishings.class) + || tmp[i].getCategory().equals(PageRanges.class) + || tmp[i].getCategory().equals(NumberUp.class) + || tmp[i].getCategory().equals(OrientationRequested.class) + || tmp[i].getCategory().equals(Media.class) + || tmp[i].getCategory().equals(PrinterResolution.class) + || tmp[i].getCategory().equals(PrintQuality.class) + || tmp[i].getCategory().equals(SheetCollate.class) + || tmp[i].getCategory().equals(Sides.class)) + + jobAttributes.add(tmp[i]); + } + } + + /** + * Does some validation of the supplied parameters and then + * sends the request to the ipp server or service. + * + * @return The response if any. + * + * @throws IllegalStateException if request is already sent + * @throws IppException if connection or request failed. + * @throws IOException if writing of the header, attributes or footer fails. + */ + public IppResponse send() throws IppException, IOException + { + if (alreadySent) + throw new IllegalStateException("Request is already sent"); + + alreadySent = true; + + OutputStream stream = connection.getOutputStream(); + DataOutputStream out = new DataOutputStream(stream); + + // the header 8 bytes long + out.writeShort(VERSION); + out.writeShort(operation_id); + out.writeInt(request_id); + + logger.log(Component.IPP, "OperationID: " + Integer.toHexString(operation_id) + + " RequestID: " + request_id); + + // Pass stuff the the attribute writer which knows how to + // write the attributes in correct order + logger.log(Component.IPP, "Operation Attributes"); + + RequestWriter writer = new RequestWriter(out); + writer.writeOperationAttributes(operationAttributes); + + if (jobAttributes != null) + { + logger.log(Component.IPP, "Job Attributes"); + out.write(IppDelimiterTag.JOB_ATTRIBUTES_TAG); + writer.writeAttributes(jobAttributes); + } + if (printerAttributes != null) + { + logger.log(Component.IPP, "Printer Attributes"); + out.write(IppDelimiterTag.PRINTER_ATTRIBUTES_TAG); + writer.writeAttributes(printerAttributes); + } + + // write the delimiter to the data + out.write(IppDelimiterTag.END_OF_ATTRIBUTES_TAG); + + // check if data is byte[] or inputstream + if (data instanceof InputStream) + { + byte[] readbuf = new byte[2048]; + int len = 0; + while( (len = ((InputStream) data).read(readbuf)) > 0) + out.write(readbuf, 0, len); + } + else if (data != null) + { + out.write((byte[]) data); + } + + out.flush(); + stream.flush(); + + // Set the connection timeout, for if the printer is offline. + // FIXME: The print services polling should probably be done in its + // own thread. + connection.setConnectTimeout( timeout ); + + int responseCode = connection.getResponseCode(); + + if (responseCode == HttpURLConnection.HTTP_OK) + { + IppResponse response = new IppResponse(requestUri, operation_id); + response.setResponseData(connection.getInputStream()); + return response; + } + + logger.log(Component.IPP, "HTTP-Statuscode: " + responseCode); + + throw new IppException("Request failed got HTTP status code " + + responseCode); + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/IppResponse.java b/libjava/classpath/gnu/javax/print/ipp/IppResponse.java new file mode 100644 index 000000000..703bdc1eb --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/IppResponse.java @@ -0,0 +1,787 @@ +/* IppResponse.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., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.javax.print.ipp; + +import gnu.classpath.debug.Component; +import gnu.classpath.debug.SystemLogger; +import gnu.javax.print.ipp.attribute.UnknownAttribute; +import gnu.javax.print.ipp.attribute.defaults.DocumentFormatDefault; +import gnu.javax.print.ipp.attribute.defaults.JobHoldUntilDefault; +import gnu.javax.print.ipp.attribute.defaults.JobSheetsDefault; +import gnu.javax.print.ipp.attribute.defaults.MediaDefault; +import gnu.javax.print.ipp.attribute.defaults.PrinterResolutionDefault; +import gnu.javax.print.ipp.attribute.job.AttributesCharset; +import gnu.javax.print.ipp.attribute.job.AttributesNaturalLanguage; +import gnu.javax.print.ipp.attribute.job.JobMoreInfo; +import gnu.javax.print.ipp.attribute.job.JobPrinterUri; +import gnu.javax.print.ipp.attribute.job.JobUri; +import gnu.javax.print.ipp.attribute.printer.CharsetConfigured; +import gnu.javax.print.ipp.attribute.printer.DocumentFormat; +import gnu.javax.print.ipp.attribute.printer.NaturalLanguageConfigured; +import gnu.javax.print.ipp.attribute.printer.PrinterCurrentTime; +import gnu.javax.print.ipp.attribute.printer.PrinterDriverInstaller; +import gnu.javax.print.ipp.attribute.supported.CharsetSupported; +import gnu.javax.print.ipp.attribute.supported.DocumentFormatSupported; +import gnu.javax.print.ipp.attribute.supported.GeneratedNaturalLanguageSupported; +import gnu.javax.print.ipp.attribute.supported.JobHoldUntilSupported; +import gnu.javax.print.ipp.attribute.supported.JobSheetsSupported; +import gnu.javax.print.ipp.attribute.supported.MediaSupported; +import gnu.javax.print.ipp.attribute.supported.PrinterResolutionSupported; +import gnu.javax.print.ipp.attribute.supported.PrinterUriSupported; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.logging.Logger; + +import javax.print.attribute.Attribute; +import javax.print.attribute.standard.CopiesSupported; +import javax.print.attribute.standard.DateTimeAtCompleted; +import javax.print.attribute.standard.DateTimeAtCreation; +import javax.print.attribute.standard.DateTimeAtProcessing; +import javax.print.attribute.standard.JobImpressionsSupported; +import javax.print.attribute.standard.JobKOctetsSupported; +import javax.print.attribute.standard.JobMediaSheetsSupported; +import javax.print.attribute.standard.JobStateReason; +import javax.print.attribute.standard.JobStateReasons; +import javax.print.attribute.standard.NumberUpSupported; +import javax.print.attribute.standard.PrinterMoreInfo; +import javax.print.attribute.standard.PrinterMoreInfoManufacturer; +import javax.print.attribute.standard.PrinterStateReason; +import javax.print.attribute.standard.PrinterStateReasons; +import javax.print.attribute.standard.Severity; + +/** + * IppResponse models a response received from an IPP + * compatible server as described in RFC 2910 IPP 1.1 Encoding and Transport. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public class IppResponse +{ + + /** + * ResponseReader is responsible for parsing an IPP 1.1 + * response stream. It provides access to the attribute groups after parsing + * via getter methods. + *

    + * The enconding of a response is structured as follows (for an official + * description please have a look at the RFC document mentioned above): + *

      + *
    • version-number - 2 bytes - required
    • + *
    • status-code - 2 bytes - required
    • + *
    • request-id - 4 bytes - required
    • + *
    • attribute-group - n bytes - 0 or more
    • + *
    • end-of-attributes-tag - 1 byte - required
    • + *
    • data - q bytes - optional
    • + *
    + *

    + * Where each attribute-group (if any) is encoded as follows: + *

      + *
    • begin-attribute-group-tag - 1 byte
    • + *
    • attribute - p bytes - 0 or more
    • + *
    + *

    + * Encoding of attributes: + *

      + *
    • attribute-with-one-value - q bytes
    • + *
    • additional-value - r bytes - 0 or more
    • + *
    + *

    + * Encoding of attribute-with-one-value: + *

      + *
    • value-tag - 1 byte
    • + *
    • name-length (value is u) - 2 bytes
    • + *
    • name - u bytes
    • + *
    • value-length (value is v) - 2 bytes
    • + *
    • value - v bytes
    • + *
    + *

    + * Encoding of additional value: + *

      + *
    • value-tag - 1 byte
    • + *
    • name-length (value is 0x0000) - 2 bytes
    • + *
    • value-length (value is w) - 2 bytes
    • + *
    • value - w bytes
    • + *
    + *

    + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ + class ResponseReader + { + /** The IPP version defaults to 1.1 */ + private static final short VERSION = 0x0101; + + /** + * Parses the inputstream containing the response of the IPP request. + * @param input the inputstream + * @throws IppException if unexpected exceptions occur. + * @throws IOException if IO problems with the underlying inputstream occur. + */ + public void parseResponse(InputStream input) + throws IppException, IOException + { + DataInputStream stream = new DataInputStream(input); + + short version = stream.readShort(); + status_code = stream.readShort(); + request_id = stream.readInt(); + + if (VERSION != version) + throw new IppException("Version mismatch - " + + "implementation does not support other versions than IPP 1.1"); + + logger.log(Component.IPP, "Statuscode: " + + Integer.toHexString(status_code) + " Request-ID: " + request_id); + + byte tag = 0; + boolean proceed = true; + HashMap, Set> tmp; + // iterate over attribute-groups until end-of-attributes-tag is found + while (proceed) + { + if (tag == 0) // only at start time + tag = stream.readByte(); + + logger.log(Component.IPP, "DelimiterTag: " + Integer.toHexString(tag)); + + // check if end of attributes + switch (tag) + { + case IppDelimiterTag.END_OF_ATTRIBUTES_TAG: + proceed = false; + break; + case IppDelimiterTag.OPERATION_ATTRIBUTES_TAG: + tmp = new HashMap, Set>(); + tag = parseAttributes(tmp, stream); + operationAttributes.add(tmp); + break; + case IppDelimiterTag.JOB_ATTRIBUTES_TAG: + tmp = new HashMap, Set>(); + tag = parseAttributes(tmp, stream); + jobAttributes.add(tmp); + break; + case IppDelimiterTag.PRINTER_ATTRIBUTES_TAG: + tmp = new HashMap, Set>(); + tag = parseAttributes(tmp, stream); + printerAttributes.add(tmp); + break; + case IppDelimiterTag.UNSUPPORTED_ATTRIBUTES_TAG: + System.out.println("Called"); + tmp = new HashMap, Set>(); + tag = parseAttributes(tmp, stream); + unsupportedAttributes.add(tmp); + break; + default: + throw new IppException("Unknown tag with value " + + Integer.toHexString(tag) + " occured."); + } + } + + // if there are more bytes that has to be data. + ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); + byte[] readbuf = new byte[2048]; + int len = 0; + + while ((len = stream.read(readbuf)) > 0) + byteStream.write(readbuf, 0, len); + + byteStream.flush(); + data = byteStream.toByteArray(); + } + + /** + * The actual parsing of the attributes and further putting into the + * provided group maps. + * @param attributes the provided attribute group map. + * @param stream the provided stream to read from. + * @return The last read tag byte (normally a DelimiterTag) + * @throws IppException if unexpected exceptions occur. + * @throws IOException if IO problems with the underlying inputstream occur. + */ + private byte parseAttributes(Map, Set> attributes, + DataInputStream stream) + throws IppException, IOException + { + Attribute lastAttribute = null; + Attribute attribute = null; + + // declaration of variables + short nameLength; + String name; + short valueLength; + byte[] value; + + // tmp variables for parsing + // declared here so no name duplication occurs + URI uri; + String str; + + while (true) + { + byte tag = stream.readByte(); + + if (IppDelimiterTag.isDelimiterTag(tag)) + return tag; + + // it must be a value tag now + // so we have either a attribute-with-one-value + // or (if setOf is possible) an additional-value + + // (1) Length of the name + nameLength = stream.readShort(); + + // (2) The name itself + // may be an additional-value + if (nameLength == 0x0000) + name = lastAttribute.getName(); + else + { + byte[] nameBytes = new byte[nameLength]; + stream.read(nameBytes); + name = new String(nameBytes); + } + + // (3) Length of the value + valueLength = stream.readShort(); + + // (4) The value itself + value = new byte[valueLength]; + stream.read(value); + + // the value itself + switch (tag) + { + // out-of-band values + case IppValueTag.UNSUPPORTED: + case IppValueTag.UNKNOWN: + // TODO implement out-of-band handling + // We currently throw an exception to see when it occurs - not yet :-) + throw new IppException( + "Unexpected name value for out-of-band value tag " + tag); + case IppValueTag.NO_VALUE: + attribute = null; + + break; + case IppValueTag.INTEGER: + int intValue = IppUtilities.convertToInt(value); + attribute = IppUtilities.getIntegerAttribute(name, intValue); + + break; + case IppValueTag.BOOLEAN: + // JPS API models boolean syntax type as enums + // 0x01 = true, 0x00 = false - all are enums + attribute = IppUtilities.getEnumAttribute(name, new Integer(value[0])); + + break; + case IppValueTag.ENUM: + int intVal = IppUtilities.convertToInt(value); + attribute = IppUtilities.getEnumAttribute(name, new Integer(intVal)); + + break; + case IppValueTag.OCTECTSTRING_UNSPECIFIED: + // none exists according to spec + // so lets report as exception to see when it occurs + throw new IppException("Unspecified octet string occured."); + + case IppValueTag.DATETIME: + Date date = parseDate(value); + if (name.equals("printer-current-time")) + attribute = new PrinterCurrentTime(date); + else if (name.equals("date-time-at-creation")) + attribute = new DateTimeAtCreation(date); + else if (name.equals("date-time-at-processing")) + attribute = new DateTimeAtProcessing(date); + else if (name.equals("date-time-at-completed")) + attribute = new DateTimeAtCompleted(date); + + break; + case IppValueTag.RESOLUTION: + int crossFeed = IppUtilities.convertToInt(value[0], value[1], value[2], value[3]); + int feed = IppUtilities.convertToInt(value[4], value[5], value[6], value[7]); + int units = value[8]; + + if (name.equals("printer-resolution-default")) + attribute = new PrinterResolutionDefault(crossFeed, feed, units); + else if (name.equals("printer-resolution-supported")) // may be here also + attribute = new PrinterResolutionSupported(crossFeed, feed, units); + + break; + case IppValueTag.RANGEOFINTEGER: + int lower = IppUtilities.convertToInt(value[0], value[1], value[2], value[3]); + int upper = IppUtilities.convertToInt(value[4], value[5], value[6], value[7]); + + if (name.equals("copies-supported")) + attribute = new CopiesSupported(lower, upper); + else if (name.equals("number-up-supported")) + attribute = new NumberUpSupported(lower, upper); + else if (name.equals("job-k-octets-supported")) + attribute = new JobKOctetsSupported(lower, upper); + else if (name.equals("job-impressions-supported")) + attribute = new JobImpressionsSupported(lower, upper); + else if (name.equals("job-media-sheets-supported")) + attribute = new JobMediaSheetsSupported(lower, upper); + + break; + case IppValueTag.TEXT_WITH_LANGUAGE: + case IppValueTag.TEXT_WITHOUT_LANGUAGE: + case IppValueTag.NAME_WITH_LANGUAGE: + case IppValueTag.NAME_WITHOUT_LANGUAGE: + attribute = IppUtilities.getTextAttribute(name, tag, value); + + break; + case IppValueTag.KEYWORD: + str = new String(value); + if (name.equals("job-hold-until-supported")) // may also be name type + attribute = new JobHoldUntilSupported(str, null); + else if (name.equals("job-hold-until-default")) + attribute = new JobHoldUntilDefault(str, null); + else if (name.equals("media-supported")) + attribute = new MediaSupported(str, null); + else if (name.equals("media-default")) + attribute = new MediaDefault(str, null); + else if (name.equals("job-sheets-default")) + attribute = new JobSheetsDefault(str, null); + else if (name.equals("job-sheets-supported")) + attribute = new JobSheetsSupported(str, null); + else if (name.equals("job-state-reasons")) // setOf + attribute = parseJobStateReasons(value, lastAttribute); + else if (name.equals("printer-state-reasons")) // setOf + attribute = parsePrinterStateReasons(value, lastAttribute); + else + attribute = IppUtilities.getEnumAttribute(name, str); + + // all other stuff is either an enum or needs to be mapped to an + // UnknownAttribute instance. Enums catched here are: + // ipp-versions-supported, pdl-override-supported, compression-supported + // uri-authentication-supported, uri-security-supported, sides-supported + // sides-default, multiple-document-handling-supported, multiple-document-handling-default + + break; + case IppValueTag.URI: + try + { + uri = new URI(new String(value)); + } + catch (URISyntaxException e) + { + throw new IppException("Wrong URI syntax encountered.", e); + } + + if (name.equals("job-uri")) + attribute = new JobUri(uri); + else if (name.equals("job-printer-uri")) + attribute = new JobPrinterUri(uri); + else if (name.equals("job-more-info")) + attribute = new JobMoreInfo(uri); + else if (name.equals("printer-uri-supported")) // setOf + attribute = new PrinterUriSupported(uri); + else if (name.equals("printer-more-info")) + attribute = new PrinterMoreInfo(uri); + else if (name.equals("printer-driver-installer")) + attribute = new PrinterDriverInstaller(uri); + else if (name.equals("printer-more-info-manufacturer")) + attribute = new PrinterMoreInfoManufacturer(uri); + + break; + case IppValueTag.URI_SCHEME: + // only one uri-scheme exists - and its an enum + if (name.equals("reference-uri-schemes-supported")) + attribute = IppUtilities.getEnumAttribute(name, new String(value)); + + break; + case IppValueTag.CHARSET: + str = new String(value); + if (name.equals("attributes-charset")) + attribute = new AttributesCharset(str); + else if (name.equals("charset-configured")) + attribute = new CharsetConfigured(str); + else if (name.equals("charset-supported")) // setOf + attribute = new CharsetSupported(str); + + break; + case IppValueTag.NATURAL_LANGUAGE: + str = new String(value); + if (name.equals("attributes-natural-language")) + attribute = new AttributesNaturalLanguage(str); + else if (name.equals("natural-language-configured")) + attribute = new NaturalLanguageConfigured(str); + else if (name.equals("generated-natural-language-supported")) // setOf + attribute = new GeneratedNaturalLanguageSupported(str); + + break; + case IppValueTag.MIME_MEDIA_TYPE: + str = new String(value); + if (name.equals("document-format-default")) + attribute = new DocumentFormatDefault(str, null); + else if (name.equals("document-format-supported")) // setOf + attribute = new DocumentFormatSupported(str, null); + else if (name.equals("document-format")) // setOf + attribute = new DocumentFormat(str, null); + + break; + default: + throw new IppException("Unknown tag with value " + + Integer.toHexString(tag) + " found."); + } + + if (attribute == null) + attribute = new UnknownAttribute(tag, name, value); + + addAttribute(attributes, attribute); + lastAttribute = attribute; + + logger.log(Component.IPP, "Attribute: " + name + + " Value: " + attribute.toString()); + } + } + + /** + * Adds a new attribute to the given attribute group. If this is the fist + * occurence of this attribute category a new set is created and associated + * with its category as key. + * @param attributeGroup + * the attribute group + * @param attribute + * the attribute to add + */ + private void addAttribute(Map, Set> attributeGroup, + Attribute attribute) + { + Class clazz = attribute.getCategory(); + Set attributeValues = attributeGroup.get(clazz); + + if (attributeValues == null) // first attribute of this category + { + attributeValues = new HashSet(); + attributeGroup.put(clazz, attributeValues); + } + + attributeValues.add(attribute); + } + + /** + * Parses a name with or without language attribute value from the byte[] + * and returns the result as an object[]. + * @param value the byte[] + * @param lastAttr the last attribute + * @return The attribute. + */ + private PrinterStateReasons parsePrinterStateReasons(byte[] value, Attribute lastAttr) + { + String str = new String(value); + PrinterStateReasons attribute; + + if (lastAttr instanceof PrinterStateReasons) + attribute = (PrinterStateReasons) lastAttr; + else + attribute = new PrinterStateReasons(); + + // special case indicating no reasons + if (str.equals("none")) + return attribute; + + Severity severity = null; + PrinterStateReason reason = null; + + if (str.endsWith(Severity.WARNING.toString())) + severity = Severity.WARNING; + else if (str.endsWith(Severity.REPORT.toString())) + severity = Severity.REPORT; + else if (str.endsWith(Severity.ERROR.toString())) + severity = Severity.ERROR; + + if (severity != null) + str = str.substring(0, str.lastIndexOf('-')); + else // we must associate a severity + severity = Severity.REPORT; + + reason = (PrinterStateReason) + IppUtilities.getEnumAttribute("printer-state-reason", str); + + attribute.put(reason , severity); + return attribute; + } + + /** + * Parses a name with or without language attribute value from the byte[] + * and returns the result as an object[]. + * @param value the byte[] + * @param lastAttr the last attribute + * @return The attribute. + */ + private JobStateReasons parseJobStateReasons(byte[] value, Attribute lastAttr) + { + String str = new String(value); + JobStateReasons attribute; + + if (lastAttr instanceof JobStateReasons) + attribute = (JobStateReasons) lastAttr; + else + attribute = new JobStateReasons(); + + // special case indicating no reasons + if (str.equals("none")) + return attribute; + + JobStateReason reason = (JobStateReason) + IppUtilities.getEnumAttribute("job-state-reason", str); + + attribute.add(reason); + return attribute; + } + + /** + * Parses a DateTime syntax attribute and returns the constructed Date + * object. + *

    + * The syntax value is defined as 11 octets follwing the DateAndTime format + * of RFC 1903: + *

      + *
    • field | octets | contents | range
    • + *
    • 1 | 1-2 | year | 0..65536
    • + *
    • 2 | 3 | month | 1..12
    • + *
    • 3 | 4 | day | 1..31
    • + *
    • 4 | 5 | hour | 0..23
    • + *
    • 5 | 6 | minutes | 0..59
    • + *
    • 6 | 7 | seconds | 0..60 (use 60 for leap-second)
    • + *
    • 7 | 8 | deci-seconds | 0..9
    • + *
    • 8 | 9 | direction from UTC | '+' / '-'
    • + *
    • 9 | 10 | hours from UTC | 0..11
    • + *
    • 10 | 11 | minutes from UTC | 0..59
    • + *
    + *

    + * + * @param value the byte[] + * @return The date object. + */ + private Date parseDate(byte[] value) + { + short year = IppUtilities.convertToShort(value[0], value[1]); + + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.YEAR, year); + cal.set(Calendar.MONTH, value[2]); + cal.set(Calendar.DAY_OF_MONTH, value[3]); + cal.set(Calendar.HOUR_OF_DAY, value[4]); + cal.set(Calendar.MINUTE, value[5]); + cal.set(Calendar.SECOND, value[6]); + cal.set(Calendar.MILLISECOND, value[7] * 100); // deci-seconds + + // offset from timezone + int offsetMilli = value[9] * 3600000; // hours to millis + offsetMilli = offsetMilli + value[10] * 60000; // minutes to millis + + if (((char) value[8]) == '-') + offsetMilli = offsetMilli * (-1); + + cal.set(Calendar.ZONE_OFFSET, offsetMilli); + return cal.getTime(); + } + } + + /** + * Logger for tracing - enable by passing + * -Dgnu.classpath.debug.components=ipp to the vm. + */ + static final Logger logger = SystemLogger.SYSTEM; + + URI uri; + short operation_id; + short status_code; + int request_id; + + List, Set>> operationAttributes; + List, Set>> printerAttributes; + List, Set>> jobAttributes; + List, Set>> unsupportedAttributes; + + byte[] data; + + /** + * Creates an IppResponse instance. + * + * @param uri the uri the request was directy to. + * @param operation_id the operation id of the request. + */ + public IppResponse(URI uri, short operation_id) + { + this.uri = uri; + this.operation_id = operation_id; + operationAttributes = + new ArrayList, Set>>(); + jobAttributes = + new ArrayList, Set>>(); + printerAttributes = + new ArrayList, Set>>(); + unsupportedAttributes = + new ArrayList, Set>>(); + } + + /** + * Sets the data received from the request sent. + * + * @param input the input stream received. + * @throws IppException if parsing fails. + */ + protected void setResponseData(InputStream input) throws IppException + { + ResponseReader reader = new ResponseReader(); + + try + { + reader.parseResponse(input); + } + catch (IOException e) + { + throw new IppException( + "Exception during response parsing caused by IOException", e); + } + } + + /** + * Returns the uri of the original request. + * @return The URI of the request. + */ + public URI getURI() + { + return uri; + } + + /** + * Returns the operation id of the original request. + * @return The operation id of the request. + */ + public int getOperationID() + { + return operation_id; + } + + /** + * Returns the set of job attributes group maps. + * There may occur more than one group of type job attribute in a response + * because of e.g. multiple job or print service informations requested. + * + * @return The list of job attribute group maps. + */ + public List, Set>> getJobAttributes() + { + return jobAttributes; + } + + /** + * Returns the set of operation attributes group maps. + * There may occur more than one group of type job attribute in a response + * because of e.g. multiple job or print service informations requested. + * + * @return The list of operation attribute group maps. + */ + public List, Set>> getOperationAttributes() + { + return operationAttributes; + } + + /** + * Returns the set of printer attributes group maps. + * There may occur more than one group of type job attribute in a response + * because of e.g. multiple job or print service informations requested. + * + * @return The list of printer attribute group maps. + */ + public List, Set>> getPrinterAttributes() + { + return printerAttributes; + } + + /** + * Returns the ID of the initial request. + * + * @return The request ID. + */ + public int getRequestID() + { + return request_id; + } + + /** + * Returns the status code of the response. + * Defined in {@link IppStatusCode}. + * + * @return The status code. + */ + public short getStatusCode() + { + return status_code; + } + + /** + * Returns the set of unsupported attributes group maps. + * There may occur more than one group of type job attribute in a response + * because of e.g. multiple job or print service informations requested. + * + * @return The list of unsupported attribute group maps. + */ + public List, Set>> getUnsupportedAttributes() + { + return unsupportedAttributes; + } + + /** + * Returns the data of the response. + * + * @return The data as byte[]. + */ + public byte[] getData() + { + return data; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/IppStatusCode.java b/libjava/classpath/gnu/javax/print/ipp/IppStatusCode.java new file mode 100644 index 000000000..a3b245c43 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/IppStatusCode.java @@ -0,0 +1,185 @@ +/* IppStatusCode.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., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.javax.print.ipp; + +/** + * IPP Status codes as described in RFC 2911 APPENDIX B + * (Status Codes and Suggested Status Code Messages) + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class IppStatusCode +{ + /** + * Indicates a successful request with no attributes being + * ignored or substituted. + */ + public static final int SUCCESSFUL_OK = 0x0000; + + /** + * Indicates a successful request, however some of the supplied + * attributes are ignored or substituted. + */ + public static final int SUCCESSFUL_OK_IGNORED_OR_SUBSTITUED_ATTRIBUTES = 0x0001; + + /** + * Indicates a successful request, however some of the supplied + * attributes conflicted and therefore were ignored or substituted. + */ + public static final int SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES = 0x0002; + + // Client Error Status Codes + // Indicates that the client has done something wrong in its + // requests send to the IPP server object + + /** Indicates a bad request e.g. malformed syntax. */ + public static final int CLIENT_ERROR_BAD_REQUEST = 0x0400; + + /** Indicates that the client is forbidden to access the server. */ + public static final int CLIENT_ERROR_FORBIDDEN = 0x0401; + + /** Indicates that the client needs to authenticate. */ + public static final int CLIENT_ERROR_NOT_AUTHENTICATED = 0x0402; + + /** Indicates that the client is not authorized. */ + public static final int CLIENT_ERROR_NOT_AUTHORIZED = 0x0403; + + /** + * Indicates a request which is not possible to process. + * For example if the request is directed at a job already finished. + */ + public static final int CLIENT_ERROR_NOT_POSSIBLE = 0x0404; + + /** Indicates that the client got a timeout for additional action. */ + public static final int CLIENT_ERROR_TIMEOUT = 0x0405; + + /** Indicates that nothing was found for the request uri. */ + public static final int CLIENT_ERROR_NOT_FOUND = 0x0406; + + /** Indicates that the requested object is gone. */ + public static final int CLIENT_ERROR_GONE = 0x0407; + + /** Indicates that the request entities are too long. */ + public static final int CLIENT_ERROR_REQUEST_ENTITY_TOO_LONG = 0x0408; + + /** Indicates that a request value is too long. */ + public static final int CLIENT_ERROR_REQUEST_VALUE_TOO_LONG = 0x0409; + + /** Indicates that the supplied document format is not supported. */ + public static final int CLIENT_ERROR_DOCUMENT_FORMAT_NOT_SUPPORTED = 0x040A; + + /** + * Indicates that the supplied attributes or values of attributes are not + * supported by the printer object. Returning this code depends on the + * given "ipp-attribute-fidelity" operation attribute value. + */ + public static final int CLIENT_ERROR_ATTRIBUTES_OR_VALUES_NOT_SUPPORTED + = 0x040B; + + /** + * Indicates the the URI scheme in a supplied print-uri or send-uri attribute + * is not supported. + */ + public static final int CLIENT_ERROR_URI_SCHEME_NOT_SUPPORTED = 0x040C; + + /** Indicates that a supplied attributes-charset is not supported. */ + public static final int CLIENT_ERROR_CHARSET_NOT_SUPPORTED = 0x040D; + + /** Indicates that conflicting attributes are in the request. */ + public static final int CLIENT_ERROR_CONFLICTING_ATTRIBUTES = 0x040E; + + /** Indicates that the specified algorithm is not supported. */ + public static final int CLIENT_ERROR_COMPRESSION_NOT_SUPPORTED = 0x040F; + + /** + * Indicates that the document cannot be decompressed with the client + * compression algorithm specified by the client. + */ + public static final int CLIENT_ERROR_COMPRESSION_ERROR = 0x0410; + + /** Indicates an error in the document format of the document. */ + public static final int CLIENT_ERROR_DOCUMENT_FORMAT_ERROR = 0x0411; + + /** + * Indicates that the document supplied via print-uri or send-uri cannot be + * accessed by the printer object. + */ + public static final int CLIENT_ERROR_DOCUMENT_ACCESS_ERROR = 0x0412; + + + /** Indicates an internal server error. */ + public static final int SERVER_ERROR_INTERNAL_ERROR = 0x0500; + + /** Indicates that the server does not support the operation. */ + public static final int SERVER_ERROR_OPERATION_NOT_SUPPORTED = 0x0501; + + /** Indicates that the server' service is not available. */ + public static final int SERVER_ERROR_SERVICE_UNAVAILABLE = 0x0502; + + /** Indicates that the server does not support the IPP version. */ + public static final int SERVER_ERROR_VERSION_NOT_SUPPORTED = 0x0503; + + /** Indicates that the server has a device error e.g. paper jam. */ + public static final int SERVER_ERROR_DEVICE_ERROR = 0x0504; + + /** Indicates that the server has a temporary error. */ + public static final int SERVER_ERROR_TEMPORARY_ERROR = 0x0505; + + /** Indicates that the server is currently not accepting jobs. */ + public static final int SERVER_ERROR_NOT_ACCEPTING_JOBS = 0x0506; + + /** + * Indicates that the server is currently busy with processing. + * Requests may be tried later again. + */ + public static final int SERVER_ERROR_BUSY = 0x0507; + + /** Indicates that the server has canceled the job for various reasons. */ + public static final int SERVER_ERROR_JOB_CANCELED = 0x0508; + + /** Indicates that the server does not support multidocument jobs. */ + public static final int SERVER_ERROR_MULTIPLE_DOCUMENT_JOBS_NOT_SUPPORTED + = 0x0509; + + private IppStatusCode() + { + // not to be instantiated + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/IppUtilities.java b/libjava/classpath/gnu/javax/print/ipp/IppUtilities.java new file mode 100644 index 000000000..fa987ec3f --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/IppUtilities.java @@ -0,0 +1,553 @@ +/* IppUtilities.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp; + +import gnu.javax.print.ipp.attribute.DetailedStatusMessage; +import gnu.javax.print.ipp.attribute.DocumentAccessError; +import gnu.javax.print.ipp.attribute.StatusMessage; +import gnu.javax.print.ipp.attribute.defaults.CopiesDefault; +import gnu.javax.print.ipp.attribute.defaults.FinishingsDefault; +import gnu.javax.print.ipp.attribute.defaults.JobHoldUntilDefault; +import gnu.javax.print.ipp.attribute.defaults.JobPriorityDefault; +import gnu.javax.print.ipp.attribute.defaults.JobSheetsDefault; +import gnu.javax.print.ipp.attribute.defaults.MediaDefault; +import gnu.javax.print.ipp.attribute.defaults.MultipleDocumentHandlingDefault; +import gnu.javax.print.ipp.attribute.defaults.NumberUpDefault; +import gnu.javax.print.ipp.attribute.defaults.OrientationRequestedDefault; +import gnu.javax.print.ipp.attribute.defaults.PrintQualityDefault; +import gnu.javax.print.ipp.attribute.defaults.SidesDefault; +import gnu.javax.print.ipp.attribute.job.JobDetailedStatusMessages; +import gnu.javax.print.ipp.attribute.job.JobDocumentAccessErrors; +import gnu.javax.print.ipp.attribute.job.JobId; +import gnu.javax.print.ipp.attribute.job.JobStateMessage; +import gnu.javax.print.ipp.attribute.printer.MultipleOperationTimeOut; +import gnu.javax.print.ipp.attribute.printer.PrinterStateMessage; +import gnu.javax.print.ipp.attribute.printer.PrinterUpTime; +import gnu.javax.print.ipp.attribute.supported.CompressionSupported; +import gnu.javax.print.ipp.attribute.supported.FinishingsSupported; +import gnu.javax.print.ipp.attribute.supported.IppVersionsSupported; +import gnu.javax.print.ipp.attribute.supported.JobHoldUntilSupported; +import gnu.javax.print.ipp.attribute.supported.JobSheetsSupported; +import gnu.javax.print.ipp.attribute.supported.MediaSupported; +import gnu.javax.print.ipp.attribute.supported.MultipleDocumentHandlingSupported; +import gnu.javax.print.ipp.attribute.supported.MultipleDocumentJobsSupported; +import gnu.javax.print.ipp.attribute.supported.OperationsSupported; +import gnu.javax.print.ipp.attribute.supported.OrientationRequestedSupported; +import gnu.javax.print.ipp.attribute.supported.PageRangesSupported; +import gnu.javax.print.ipp.attribute.supported.PrintQualitySupported; +import gnu.javax.print.ipp.attribute.supported.PrinterResolutionSupported; +import gnu.javax.print.ipp.attribute.supported.SidesSupported; +import gnu.javax.print.ipp.attribute.supported.UriAuthenticationSupported; +import gnu.javax.print.ipp.attribute.supported.UriSecuritySupported; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.Locale; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; +import javax.print.attribute.SupportedValuesAttribute; +import javax.print.attribute.standard.Chromaticity; +import javax.print.attribute.standard.ColorSupported; +import javax.print.attribute.standard.Compression; +import javax.print.attribute.standard.Copies; +import javax.print.attribute.standard.CopiesSupported; +import javax.print.attribute.standard.Fidelity; +import javax.print.attribute.standard.Finishings; +import javax.print.attribute.standard.JobHoldUntil; +import javax.print.attribute.standard.JobImpressionsCompleted; +import javax.print.attribute.standard.JobKOctetsProcessed; +import javax.print.attribute.standard.JobMediaSheetsCompleted; +import javax.print.attribute.standard.JobMessageFromOperator; +import javax.print.attribute.standard.JobName; +import javax.print.attribute.standard.JobOriginatingUserName; +import javax.print.attribute.standard.JobPriority; +import javax.print.attribute.standard.JobPrioritySupported; +import javax.print.attribute.standard.JobSheets; +import javax.print.attribute.standard.JobState; +import javax.print.attribute.standard.JobStateReason; +import javax.print.attribute.standard.Media; +import javax.print.attribute.standard.MediaSizeName; +import javax.print.attribute.standard.MultipleDocumentHandling; +import javax.print.attribute.standard.NumberOfInterveningJobs; +import javax.print.attribute.standard.NumberUp; +import javax.print.attribute.standard.NumberUpSupported; +import javax.print.attribute.standard.OrientationRequested; +import javax.print.attribute.standard.OutputDeviceAssigned; +import javax.print.attribute.standard.PDLOverrideSupported; +import javax.print.attribute.standard.PageRanges; +import javax.print.attribute.standard.PagesPerMinute; +import javax.print.attribute.standard.PagesPerMinuteColor; +import javax.print.attribute.standard.PresentationDirection; +import javax.print.attribute.standard.PrintQuality; +import javax.print.attribute.standard.PrinterInfo; +import javax.print.attribute.standard.PrinterIsAcceptingJobs; +import javax.print.attribute.standard.PrinterLocation; +import javax.print.attribute.standard.PrinterMakeAndModel; +import javax.print.attribute.standard.PrinterMessageFromOperator; +import javax.print.attribute.standard.PrinterName; +import javax.print.attribute.standard.PrinterResolution; +import javax.print.attribute.standard.PrinterState; +import javax.print.attribute.standard.PrinterStateReason; +import javax.print.attribute.standard.QueuedJobCount; +import javax.print.attribute.standard.ReferenceUriSchemesSupported; +import javax.print.attribute.standard.Severity; +import javax.print.attribute.standard.SheetCollate; +import javax.print.attribute.standard.Sides; + +/** + * Collection of static utilities methods used in + * IPP response parsing and all over the place. + *

    + * Also provides mapping from the attribute name values to + * the actual class object. Used to construct objects via reflection. + *

    + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class IppUtilities +{ + // These are reused in the reflection code to not instantiate an array everytime + private static Object[] INTEGER_ATT_VALUE = new Object[1]; + private static Class[] INTEGER_CLASS_ARRAY = new Class[] {int.class}; + private static Object[] TEXT_ATT_VALUE = new Object[2]; + private static Class[] TEXT_CLASS_ARRAY = new Class[] {String.class, Locale.class}; + + // The map -> Attribute name to Attribute class + private static HashMap> classesByName = + new HashMap>(); + // The map -> StandardAttribute class to SupportedAttribute category name + private static HashMap,SupportedValuesAttribute> instanceByClass = + new HashMap,SupportedValuesAttribute>(); + + /** + * All the currently needed attributes + */ + static + { + // enums + classesByName.put(JobState.ABORTED.getName(), JobState.class); + classesByName.put(Sides.DUPLEX.getName(), Sides.class); + classesByName.put(SheetCollate.COLLATED.getName(), SheetCollate.class); + classesByName.put(Severity.ERROR.getName(), Severity.class); + classesByName.put(JobSheets.NONE.getName(), JobSheets.class); + classesByName.put(Finishings.BIND.getName(), Finishings.class); + classesByName.put(Fidelity.FIDELITY_FALSE.getName(), Fidelity.class); + classesByName.put(Compression.GZIP.getName(), Compression.class); + classesByName.put(Chromaticity.COLOR.getName(), Chromaticity.class); + classesByName.put(PrintQuality.DRAFT.getName(), PrintQuality.class); + classesByName.put(PrinterState.IDLE.getName(), PrinterState.class); + classesByName.put(SidesDefault.ONE_SIDED.getName(), SidesDefault.class); + classesByName.put(ReferenceUriSchemesSupported.FILE.getName(), + ReferenceUriSchemesSupported.class); + classesByName.put(PrinterStateReason.DOOR_OPEN.getName(), + PrinterStateReason.class); + classesByName.put(PresentationDirection.TOLEFT_TOTOP.getName(), + PresentationDirection.class); + classesByName.put(PDLOverrideSupported.ATTEMPTED.getName(), + PDLOverrideSupported.class); + classesByName.put(OrientationRequested.PORTRAIT.getName(), + OrientationRequested.class); + classesByName.put(MultipleDocumentHandling.SINGLE_DOCUMENT.getName(), + MultipleDocumentHandling.class); + classesByName.put(JobStateReason.JOB_QUEUED.getName(), + JobStateReason.class); + classesByName.put(UriAuthenticationSupported.NONE.getName(), + UriAuthenticationSupported.class); + classesByName.put(OperationsSupported.GET_JOBS.getName(), + OperationsSupported.class); + classesByName.put(UriSecuritySupported.NONE.getName(), + UriSecuritySupported.class); + classesByName.put(FinishingsSupported.NONE.getName(), + FinishingsSupported.class); + classesByName.put(FinishingsDefault.NONE.getName(), + FinishingsDefault.class); + classesByName.put(IppVersionsSupported.V_1_0.getName(), + IppVersionsSupported.class); + classesByName.put(MultipleDocumentHandlingSupported.SINGLE_DOCUMENT.getName(), + MultipleDocumentHandlingSupported.class); + classesByName.put(MultipleDocumentHandlingDefault.SINGLE_DOCUMENT.getName(), + MultipleDocumentHandlingDefault.class); + classesByName.put(CompressionSupported.NONE.getName(), + CompressionSupported.class); + classesByName.put(OrientationRequestedSupported.PORTRAIT.getName(), + OrientationRequestedSupported.class); + classesByName.put(OrientationRequestedDefault.PORTRAIT.getName(), + OrientationRequestedDefault.class); + classesByName.put(SidesSupported.ONE_SIDED.getName(), + SidesSupported.class); + classesByName.put(PrintQualityDefault.DRAFT.getName(), + PrintQualityDefault.class); + classesByName.put(PrintQualitySupported.DRAFT.getName(), + PrintQualitySupported.class); + classesByName.put(ReferenceUriSchemesSupported.FTP.getName(), + ReferenceUriSchemesSupported.class); + + // the boolean types + classesByName.put(ColorSupported.SUPPORTED.getName(), ColorSupported.class); + classesByName.put(PrinterIsAcceptingJobs.ACCEPTING_JOBS.getName(), + PrinterIsAcceptingJobs.class); + classesByName.put(MultipleDocumentJobsSupported.SUPPORTED.getName(), + MultipleDocumentJobsSupported.class); + classesByName.put(PageRangesSupported.SUPPORTED.getName(), + PageRangesSupported.class); + + // TextSyntax derived attributes + classesByName.put("media-default", MediaDefault.class); + classesByName.put("media-supported", MediaSupported.class); + classesByName.put("media", MediaSizeName.class); + classesByName.put("printer-location", PrinterLocation.class); + classesByName.put("printer-info", PrinterInfo.class); + classesByName.put("printer-make-and-model", PrinterMakeAndModel.class); + classesByName.put("printer-state-message", PrinterStateMessage.class); + classesByName.put("job-state-message", JobStateMessage.class); + classesByName.put("job-sheets-default", JobSheetsDefault.class); + classesByName.put("job-sheets-supported", JobSheetsSupported.class); + classesByName.put("job-name", JobName.class); + classesByName.put("printer-name", PrinterName.class); + classesByName.put("status-message", StatusMessage.class); + classesByName.put("detailed-status-message", DetailedStatusMessage.class); + classesByName.put("document-access-error", DocumentAccessError.class); + classesByName.put("output-device-assigned", OutputDeviceAssigned.class); + classesByName.put("job-hold-until-default", JobHoldUntilDefault.class); + classesByName.put("job-originating-user-name", + JobOriginatingUserName.class); + classesByName.put("job-hold-until-supported", + JobHoldUntilSupported.class); + classesByName.put("job-message-from-operator", + JobMessageFromOperator.class); + classesByName.put("printer-message-from-operator", + PrinterMessageFromOperator.class); + classesByName.put("job-detailed-status-messages", + JobDetailedStatusMessages.class); + classesByName.put("job-document-access-errors", + JobDocumentAccessErrors.class); + + // IntegerSyntax derived Attributes + classesByName.put("copies-default", CopiesDefault.class); + classesByName.put("job-id", JobId.class); + classesByName.put("job-priority-supported", JobPrioritySupported.class); + classesByName.put("job-priority-default", JobPriorityDefault.class); + classesByName.put("number-up-supported", NumberUpSupported.class); + classesByName.put("number-up-default", NumberUpDefault.class); + classesByName.put("queued-job-count", QueuedJobCount.class); + classesByName.put("printer-up-time", PrinterUpTime.class); + classesByName.put("pages-per-minute", PagesPerMinute.class); + classesByName.put("pages-per-minute-color", PagesPerMinuteColor.class); + classesByName.put("job-k-octets-processed", JobKOctetsProcessed.class); + classesByName.put("number-of-intervening-jobs", + NumberOfInterveningJobs.class); + classesByName.put("job-impressions-completed", + JobImpressionsCompleted.class); + classesByName.put("job-media-sheets-completed", + JobMediaSheetsCompleted.class); + classesByName.put("multiple-operation-time-out", + MultipleOperationTimeOut.class); + + + // 4.2 job template attributes + instanceByClass.put(JobPriority.class, new JobPrioritySupported(1)); + instanceByClass.put(JobHoldUntil.class, new JobHoldUntilSupported("", null)); + instanceByClass.put(JobSheets.class, new JobSheetsSupported("", null)); + instanceByClass.put(MultipleDocumentHandling.class, MultipleDocumentHandlingSupported.SINGLE_DOCUMENT); + instanceByClass.put(Copies.class, new CopiesSupported(1)); + instanceByClass.put(Finishings.class, FinishingsSupported.BIND); + instanceByClass.put(PageRanges.class, PageRangesSupported.SUPPORTED); + instanceByClass.put(Sides.class, SidesSupported.DUPLEX); + instanceByClass.put(NumberUp.class, new NumberUpSupported(1)); + instanceByClass.put(OrientationRequested.class, OrientationRequestedSupported.LANDSCAPE); + instanceByClass.put(Media.class, new MediaSupported("", null)); + instanceByClass.put(PrinterResolution.class, new PrinterResolutionSupported(1,1,1)); + instanceByClass.put(PrintQuality.class, PrintQualitySupported.DRAFT); + + // 4.4 printer attributes + instanceByClass.put(Compression.class, CompressionSupported.COMPRESS); + } + + private IppUtilities() + { + // not to be instantiated + } + + /** + * Returns the implementing class object for given + * attribute name objects. + * + * @param name the attribute name + * @return The Class object. + */ + public static Class getClass(String name) + { + return classesByName.get(name); + } + + /** + * Returns the name of the supported attribute + * based on the given standard attribute category. + * + * @param clazz the standard attribute category + * @return The name of the supported attribute category. + */ + public static String getSupportedAttrName(Class clazz) + { + return instanceByClass.get(clazz).getName(); + } + + /** + * Returns the category of the supported attribute + * based on the given standard attribute category. + * + * @param clazz the standard attribute category + * @return The supported attribute category. + */ + public static Class getSupportedCategory(Class clazz) + { + return instanceByClass.get(clazz).getCategory(); + } + + /** + * Helper method to convert to an int. + * @param b the byte array + * @return The converted int. + */ + public static int convertToInt(byte[] b) + { + return (((b[0] & 0xff) << 24) | ((b[1] & 0xff) << 16) + | ((b[2] & 0xff) << 8) | (b[3] & 0xff)); + } + + /** + * Helper method to convert to an int. + * @param b1 the 1th byte + * @param b2 the 2th byte + * @param b3 the 3th byte + * @param b4 the 4th byte + * @return The converted int. + */ + public static int convertToInt(byte b1, byte b2, byte b3, byte b4) + { + return (((b1 & 0xff) << 24) | ((b2 & 0xff) << 16) + | ((b3 & 0xff) << 8) | (b4 & 0xff)); + } + + /** + * Helper method to convert to a short. + * @param b1 the 1th byte + * @param b2 the 2th byte + * @return The converted short. + */ + public static short convertToShort(byte b1, byte b2) + { + return (short) ((b1 << 8) | (b2 & 0xff)); + } + + /** + * Instantiates an EnumSyntax based attribute with the given IPP + * name and the given value (Enums maybe int or String based). + * + * @param name the attribute name of the subclass. + * @param value the integer value of the specific enum. + * @return The Attribute (a subclass of EnumSyntax) + */ + public static Attribute getEnumAttribute(String name, Object value) + { + Class attrClass = getClass(name); + + // There might be unknown enums we have no mapped class for + if (attrClass == null) + return null; + + try + { + Field[] fields = attrClass.getDeclaredFields(); + for (int i = 0; i < fields.length; i++) + { + Field field = fields[i]; + if (field.getType().equals(attrClass)) + { + EnumSyntax attr = (EnumSyntax) field.get(null); + if (value instanceof Integer + && attr.getValue() == ((Integer) value).intValue()) + return (Attribute) attr; + else if (value instanceof String + && attr.toString().equals(value)) + return (Attribute) attr; + } + } + } + catch (SecurityException e) + { + // should not happen + } + catch (IllegalArgumentException e) + { + // should not happen + } + catch (IllegalAccessException e) + { + // should not happen, all fields are public + } + + return null; + } + + + + /** + * Instantiates an IntegerSyntax based attribute with the + * given IPP name for the given int value. + * + * @param name the attribute name of the subclass. + * @param value the integer value + * @return The Attribute (a subclass of IntegerSyntax) + */ + public static Attribute getIntegerAttribute(String name, int value) + { + Class attrClass = getClass(name); + + // There might be unknown attributes we have no mapped class for + if (attrClass == null) + return null; + + try + { + INTEGER_ATT_VALUE[0] = Integer.valueOf(value); + Constructor c = attrClass.getDeclaredConstructor(INTEGER_CLASS_ARRAY); + return (Attribute) c.newInstance(INTEGER_ATT_VALUE); + } + catch (SecurityException e) + { + // should not happen + } + catch (NoSuchMethodException e) + { + // should not happen + } + catch (IllegalAccessException e) + { + // should not happen, all fields are public + } + catch (InstantiationException e) + { + // should not happen, all fields are public + } + catch (InvocationTargetException e) + { + // should not happen, all fields are public + } + + return null; + } + + /** + * Instantiates an TextSyntax based attribute with the given + * IPP name for the given text value (will be decoded). + * + * @param name the attribute name of the subclass. + * @param tag the tag defined in {@link IppValueTag} + * @param value the byte[] value to be decoded based on the tag value. + * @return The Attribute (a subclass of TextSyntax) + */ + public static Attribute getTextAttribute(String name, byte tag, byte[] value) + { + // without language tag is rather easy - default locale + if (tag == IppValueTag.NAME_WITHOUT_LANGUAGE + || tag == IppValueTag.TEXT_WITHOUT_LANGUAGE) + { + TEXT_ATT_VALUE[0] = new String(value); + TEXT_ATT_VALUE[1] = Locale.getDefault(); + } + else + { + short langLength = convertToShort(value[0], value[1]); + byte[] tmp = new byte[langLength]; + byte[] tmp2 = new byte[value.length - 4 - langLength]; + System.arraycopy(value, 2, tmp, 0, langLength); + + // parse into language/region + String language = new String(tmp); + String text = new String(tmp2); + Locale locale = null; + + if (language.length() > 2) + locale = new Locale(language.substring(0, 2), language.substring(3)); + else + locale = new Locale(language); + + TEXT_ATT_VALUE[0] = text; + TEXT_ATT_VALUE[1] = locale; + } + + Class attrClass = getClass(name); + + // There might be unknown attributes we have no mapped class for + if (attrClass == null) + return null; + + try + { + Constructor c = attrClass.getDeclaredConstructor(TEXT_CLASS_ARRAY); + return (Attribute) c.newInstance(TEXT_ATT_VALUE); + } + catch (SecurityException e) + { + // should not happen + } + catch (NoSuchMethodException e) + { + // should not happen + } + catch (IllegalAccessException e) + { + // should not happen, all fields are public + } + catch (InstantiationException e) + { + // should not happen, all fields are public + } + catch (InvocationTargetException e) + { + // should not happen, all fields are public + } + + return null; + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/IppValueTag.java b/libjava/classpath/gnu/javax/print/ipp/IppValueTag.java new file mode 100644 index 000000000..def9545a3 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/IppValueTag.java @@ -0,0 +1,170 @@ +/* IppValueTag.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp; + +/** + * IPP Value Tags as described in RFC 2910 section 3.5.2. + *

    + * Attributes are always of a special type syntax (e.g. boolean or + * interger attribute). These value types are specified by the tag + * constants provided in this class. Beside the syntax types some + * out of band values for reporting requested attributes as + * unsupported, unknown etc. back to the client. + *

    + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class IppValueTag +{ + + /** Out of band value for unsupported attributes. */ + public static final byte UNSUPPORTED = 0x10; + + // 0x11 reserved for 'default' for definition in a future + // IETF standards track document + + /** Out of band value for unknown attributes. */ + public static final byte UNKNOWN = 0x12; + + /** Out of band value for attribute without a value. */ + public static final byte NO_VALUE = 0x13; + + // 0x14-0x1F reserved for "out-of-band" values in future IETF + // standards track documents. + + // 0x20 reserved for definition in a future IETF + // standards track document + + /** Indicates a value of syntax type integer. */ + public static final byte INTEGER = 0x21; + + /** Indicates a value of syntax type boolean. */ + public static final byte BOOLEAN = 0x22; + + /** Indicates a value of syntax type enum (enumeration). */ + public static final byte ENUM = 0x23; + + // 0x24-0x2F reserved for integer types for definition in + // future IETF standards track documents + + /** Indicates a value of syntax type octect string. */ + public static final byte OCTECTSTRING_UNSPECIFIED = 0x30; + + /** Indicates a value of syntax type datetime. */ + public static final byte DATETIME = 0x31; + + /** Indicates a value of syntax type resolution. */ + public static final byte RESOLUTION = 0x32; + + /** Indicates a value of syntax type range of integers. */ + public static final byte RANGEOFINTEGER = 0x33; + + // 0x34 reserved for definition in a future IETF + // standards track document + + /** Indicates a value of syntax type text with language. */ + public static final byte TEXT_WITH_LANGUAGE = 0x35; + + /** Indicates a value of syntax type name with language. */ + public static final byte NAME_WITH_LANGUAGE = 0x36; + + // 0x37-0x3F reserved for octetString type definitions in + // future IETF standards track documents + + // 0x40 reserved for definition in a future IETF + // standards track document + + /** Indicates a value of syntax type text without language. */ + public static final byte TEXT_WITHOUT_LANGUAGE = 0x41; + + /** Indicates a value of syntax type name without language. */ + public static final byte NAME_WITHOUT_LANGUAGE = 0x42; + + // 0x43 reserved for definition in a future IETF + // standards track document + + /** Indicates a value of syntax type keyword. */ + public static final byte KEYWORD = 0x44; + + /** Indicates a value of syntax type URI. */ + public static final byte URI = 0x45; + + /** Indicates a value of syntax type URI scheme. */ + public static final byte URI_SCHEME = 0x46; + + /** Indicates a value of syntax type charset. */ + public static final byte CHARSET = 0x47; + + /** Indicates a value of syntax type language. */ + public static final byte NATURAL_LANGUAGE =0x48; + + /** Indicates a value of syntax type mime media. */ + public static final byte MIME_MEDIA_TYPE = 0x49; + + // 0x4A-0x5F reserved for character string type definitions + // in future IETF standards track documents + + + private IppValueTag() + { + // not to be instantiated; + } + + /** + * Tests if given value corresponds to a + * value tag value. + * + * @param value the value to test for + * @return true if, false otherwise. + */ + public static boolean isValueTag(byte value) + { + if(value == 0x10 || value == 0x12 || value == 0x13 + || value == 0x21 || value == 0x22 || value == 0x23 + || value == 0x30 || value == 0x31 || value == 0x32 + || value == 0x33 || value == 0x35 || value == 0x36 + || value == 0x41 || value == 0x42 || value == 0x44 + || value == 0x45 || value == 0x46 || value == 0x47 + || value == 0x48 || value == 0x49 ) + return true; + + return false; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/MultiDocPrintJobImpl.java b/libjava/classpath/gnu/javax/print/ipp/MultiDocPrintJobImpl.java new file mode 100644 index 000000000..89163dc99 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/MultiDocPrintJobImpl.java @@ -0,0 +1,80 @@ +/* MultiDocPrintJobImpl.java -- GNU implementation of MultiDocPrintJob + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp; + + +import javax.print.MultiDoc; +import javax.print.MultiDocPrintJob; +import javax.print.PrintException; +import javax.print.attribute.PrintRequestAttributeSet; + +/** + * Implementation of the MultiDocPrintJob interface. Implementation + * is specific to the IppPrintService implementation. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public class MultiDocPrintJobImpl extends DocPrintJobImpl + implements MultiDocPrintJob +{ + + /** + * Constructor forwarding arguments to the super constructor. + * + * @param service the print service instance. + * @param user the user of this print service. + * @param passwd the password of the user. + */ + public MultiDocPrintJobImpl(IppPrintService service, String user, + String passwd) + { + super(service, user, passwd); + } + + /** + * @see MultiDocPrintJob#print(MultiDoc, PrintRequestAttributeSet) + */ + public void print(MultiDoc multiDoc, PrintRequestAttributeSet attributes) + throws PrintException + { + // FIXME Implement + throw new PrintException("Multidoc not yet supported by implementation."); + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/CharsetSyntax.java b/libjava/classpath/gnu/javax/print/ipp/attribute/CharsetSyntax.java new file mode 100644 index 000000000..cd112f459 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/CharsetSyntax.java @@ -0,0 +1,115 @@ +/* CharsetSyntax.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute; + +import java.io.Serializable; + +/** + * CharsetSyntax is the abstract base class of all attribute + * classes which provide a charset (US-ASCII) string as value. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public abstract class CharsetSyntax implements Cloneable, Serializable +{ + private final String value; + + /** + * Creates a CharsetSyntax object with the given value + * and locale. + * + * @param value the value for this syntax + * + * @exception NullPointerException if value is null + */ + protected CharsetSyntax(String value) + { + if (value == null) + throw new NullPointerException("value may not be null"); + + this.value = value; + } + + /** + * Returns the value of this syntax object. + * + * @return The value. + */ + public String getValue() + { + return value; + } + + /** + * Returns the hashcode for this object. + * + * @return The hashcode. + */ + public int hashCode() + { + return value.hashCode(); + } + + /** + * Tests if the given object is equal to this object. + * + * @param obj the object to test + * + * @return true if both objects are equal, false otherwise. + */ + public boolean equals(Object obj) + { + if (! (obj instanceof CharsetSyntax)) + return false; + + CharsetSyntax tmp = (CharsetSyntax) obj; + return value.equals(tmp.getValue()); + } + + /** + * Returns a string representing the object. The returned + * string is the underlying text value of this object. + * + * @return The string representation. + */ + public String toString() + { + return getValue(); + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/DefaultValueAttribute.java b/libjava/classpath/gnu/javax/print/ipp/attribute/DefaultValueAttribute.java new file mode 100644 index 000000000..cc40db22e --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/DefaultValueAttribute.java @@ -0,0 +1,59 @@ +/* DefaultValueAttribute.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute; + +import javax.print.attribute.Attribute; + +/** + * Marker interface for all attribute classes describing attributes + * providing default values. Often there exist a sequence of an + * attribute name like: Name - > Name-default -> Name-supported. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public interface DefaultValueAttribute extends Attribute +{ + /** + * Returns the equally enum of the standard attribute class + * of this SupportedValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public Attribute getAssociatedAttribute(); +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/DetailedStatusMessage.java b/libjava/classpath/gnu/javax/print/ipp/attribute/DetailedStatusMessage.java new file mode 100644 index 000000000..2d005a82e --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/DetailedStatusMessage.java @@ -0,0 +1,93 @@ +/* DetailedStatusMessage.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute; + +import java.util.Locale; + +import javax.print.attribute.Attribute; +import javax.print.attribute.TextSyntax; + +/** + * DetailedStatusMessage attribute as described in RFC 2911 section + * 3.1.6 Operation Response Status Codes and Status Message + * provides a short description of the status of the operation. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class DetailedStatusMessage extends TextSyntax + implements Attribute +{ + + /** + * Creates a DetailedStatusMessage object with the given value + * and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @exception NullPointerException if value is null + */ + public DetailedStatusMessage(String value, Locale locale) + { + super(value, locale); + } + + /** + * Returns category of this class. + * + * @return The class DetailedStatusMessage itself. + */ + public Class getCategory() + { + return DetailedStatusMessage.class; + } + + + /** + * Returns the name of this attribute. + * + * @return The name "detailed-status-message". + */ + public String getName() + { + return "detailed-status-message"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/DocumentAccessError.java b/libjava/classpath/gnu/javax/print/ipp/attribute/DocumentAccessError.java new file mode 100644 index 000000000..56b55ba76 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/DocumentAccessError.java @@ -0,0 +1,93 @@ +/* DocumentAccessError.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute; + +import java.util.Locale; + +import javax.print.attribute.Attribute; +import javax.print.attribute.TextSyntax; + +/** + * DocumentAccessError attribute as described in RFC 2911 section + * 3.1.6 Operation Response Status Codes and Status Message + * provides additional information for document access errors. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class DocumentAccessError extends TextSyntax + implements Attribute +{ + + /** + * Creates a DocumentAccessError object with the given value + * and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @exception NullPointerException if value is null + */ + public DocumentAccessError(String value, Locale locale) + { + super(value, locale); + } + + /** + * Returns category of this class. + * + * @return The class DocumentAccessError itself. + */ + public Class getCategory() + { + return DocumentAccessError.class; + } + + + /** + * Returns the name of this attribute. + * + * @return The name "document-access-error". + */ + public String getName() + { + return "document-access-error"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/NaturalLanguageSyntax.java b/libjava/classpath/gnu/javax/print/ipp/attribute/NaturalLanguageSyntax.java new file mode 100644 index 000000000..a648c8cec --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/NaturalLanguageSyntax.java @@ -0,0 +1,117 @@ +/* NaturalLanguageSyntax.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute; + +import java.io.Serializable; + +/** + * NaturalLanguageSyntax is the abstract base class of all + * attribute classes which provide a natural language (US-ASCII) + * string as value. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public abstract class NaturalLanguageSyntax + implements Cloneable, Serializable +{ + private final String value; + + /** + * Creates a NaturalLanguageSyntax object with the given value + * and locale. + * + * @param value the value for this syntax + * + * @exception NullPointerException if value is null + */ + protected NaturalLanguageSyntax(String value) + { + if (value == null) + throw new NullPointerException("value may not be null"); + + this.value = value; + } + + /** + * Returns the value of this syntax object. + * + * @return The value. + */ + public String getValue() + { + return value; + } + + /** + * Returns the hashcode for this object. + * + * @return The hashcode. + */ + public int hashCode() + { + return value.hashCode(); + } + + /** + * Tests if the given object is equal to this object. + * + * @param obj the object to test + * + * @return true if both objects are equal, false otherwise. + */ + public boolean equals(Object obj) + { + if (! (obj instanceof NaturalLanguageSyntax)) + return false; + + NaturalLanguageSyntax tmp = (NaturalLanguageSyntax) obj; + return value.equals(tmp.getValue()); + } + + /** + * Returns a string representing the object. The returned + * string is the underlying text value of this object. + * + * @return The string representation. + */ + public String toString() + { + return getValue(); + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/RequestedAttributes.java b/libjava/classpath/gnu/javax/print/ipp/attribute/RequestedAttributes.java new file mode 100644 index 000000000..4c129f6d5 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/RequestedAttributes.java @@ -0,0 +1,132 @@ +/* RequestedAttributes.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute; + +import gnu.java.lang.CPStringBuilder; + +import java.util.ArrayList; +import java.util.List; + +import javax.print.attribute.Attribute; + +/** + * RequestedAttributes specifies the requested + * attributes in an IPP request operation. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class RequestedAttributes implements Attribute +{ + private ArrayList attributes; + + /** + * Creates a RequestedAttributes object with + * the initial value. + * + * @param value the string for the ipp name + * + * @exception NullPointerException if value is null + */ + public RequestedAttributes(String value) + { + if (value == null) + throw new NullPointerException(); + + attributes = new ArrayList(); + attributes.add(value); + } + + /** + * Adds the IPP name value to the set. + * + * @param value the string for the ipp name + */ + public void addValue(String value) + { + attributes.add(value); + } + + /** + * Returns the values. + * + * @return The values as list. + */ + public String[] getValues() + { + return attributes.toArray(new String[attributes.size()]); + } + + /** + * Returns category of this class. + * + * @return The class DocumentFormat itself. + */ + public Class getCategory() + { + return RequestedAttributes.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "requested-attributes". + */ + public String getName() + { + return "requested-attributes"; + } + + /** + * Returns the string representation for this object. + * + * @return The string representation. + */ + public String toString() + { + CPStringBuilder b = new CPStringBuilder(); + + if (attributes.size() > 0) + b.append(attributes.get(0)); + + for (int i=1; i < attributes.size(); i++) + b.append(", " + attributes.get(i)); + + return b.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/StatusMessage.java b/libjava/classpath/gnu/javax/print/ipp/attribute/StatusMessage.java new file mode 100644 index 000000000..0701008ef --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/StatusMessage.java @@ -0,0 +1,92 @@ +/* StatusMessage.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute; + +import java.util.Locale; + +import javax.print.attribute.Attribute; +import javax.print.attribute.TextSyntax; + +/** + * StatusMessage attribute as described in RFC 2911 section + * 3.1.6 Operation Response Status Codes and Status Message + * provides a short description of the status of the operation. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class StatusMessage extends TextSyntax implements Attribute +{ + + /** + * Creates a StatusMessage object with the given value + * and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @exception NullPointerException if value is null + */ + public StatusMessage(String value, Locale locale) + { + super(value, locale); + } + + /** + * Returns category of this class. + * + * @return The class StatusMessage itself. + */ + public Class getCategory() + { + return StatusMessage.class; + } + + + /** + * Returns the name of this attribute. + * + * @return The name "status-message". + */ + public String getName() + { + return "status-message"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/UnknownAttribute.java b/libjava/classpath/gnu/javax/print/ipp/attribute/UnknownAttribute.java new file mode 100644 index 000000000..a03beccbe --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/UnknownAttribute.java @@ -0,0 +1,190 @@ +/* UnknownAttribute.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute; + +import gnu.javax.print.ipp.IppUtilities; +import gnu.javax.print.ipp.IppValueTag; + +import java.net.URI; +import java.net.URISyntaxException; + +import javax.print.attribute.Attribute; + +/** + * UnknownAttribute holds all the parsed Attribute information. + * It provides methods to get the value-tag, name and value. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class UnknownAttribute implements Attribute +{ + private byte tag; + private String name; + private byte[] value; + + /** + * Creates a UnknownAttribute object with the given values. + * + * @param tag the value tag + * @param name the attribute name + * @param value the byte[] with the value + */ + public UnknownAttribute(byte tag, String name, byte[] value) + { + this.tag = tag; + this.name = name; + this.value = value; + } + + /** + * Returns category of this class. + * + * @return The class UnknownAttribute itself. + */ + public Class getCategory() + { + return UnknownAttribute.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name attributes IPP name. + */ + public String getName() + { + return name; + } + + /** + * Returns the value tag + * @return The tag. + * + * @see gnu.javax.print.ipp.IppValueTag + */ + public byte getValueTag() + { + return tag; + } + + /** + * Returns the name of the attribute. + * @return The name. + */ + public String getAttributeName() + { + return name; + } + + /** + * Returns the attribute value origin byte array. + * @return The value. + */ + public byte[] getAttributeValue() + { + return value; + } + + /** + * Returns the attribute value decoded as String. + * @return The value as String. + */ + public String getAttributeValueAsString() + { + return new String(value); + } + + /** + * Returns the attribute value decoded as int. + * @return The value as int. + */ + public int getAttributeValueAsInt() + { + return IppUtilities.convertToInt(value); + } + + /** + * Returns the attribute value decoded as an URI. + * @return The value as URI. + */ + public URI getAttributeValueAsUri() + { + try + { + return new URI(new String(value)); + } + catch (URISyntaxException e) + { + return null; + } + } + + /** + * Provides a string representation for some default + * tag types (e.g. int, rangeofinteger, string, uri). + * For other more complex types "No conversion found." + * is returned. + */ + public String toString() + { + switch (tag) + { + case IppValueTag.INTEGER: + return "" + getAttributeValueAsInt(); + case IppValueTag.RANGEOFINTEGER: + int lower = IppUtilities.convertToInt(value[0], value[1], + value[2], value[3]); + int upper = IppUtilities.convertToInt(value[4], value[5], + value[6], value[7]); + return lower + "-" + upper; + case IppValueTag.URI: + return getAttributeValueAsUri().toString(); + case IppValueTag.KEYWORD: + case IppValueTag.URI_SCHEME: + case IppValueTag.CHARSET: + case IppValueTag.NATURAL_LANGUAGE: + case IppValueTag.MIME_MEDIA_TYPE: + case IppValueTag.NAME_WITHOUT_LANGUAGE: + case IppValueTag.TEXT_WITHOUT_LANGUAGE: + return getAttributeValueAsString(); + default: + return "No conversion found."; + } + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/CopiesDefault.java b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/CopiesDefault.java new file mode 100644 index 000000000..39d8fe1c0 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/CopiesDefault.java @@ -0,0 +1,118 @@ +/* CopiesDefault.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.print.ipp.attribute.defaults; + +import gnu.javax.print.ipp.attribute.DefaultValueAttribute; + +import javax.print.attribute.Attribute; +import javax.print.attribute.IntegerSyntax; +import javax.print.attribute.standard.Copies; + +/** + * CopiesDefault provides the default value + * for the copies attribute. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class CopiesDefault extends IntegerSyntax + implements DefaultValueAttribute +{ + + /** + * Creates a CopiesDefault object. + * + * @param value the number of copies + * + * @exception IllegalArgumentException if value < 1 + */ + public CopiesDefault(int value) + { + super(value); + + if (value < 1) + throw new IllegalArgumentException("value may not be less than 1"); + } + + /** + * Tests if the given object is equal to this object. + * + * @param obj the object to test + * + * @return true if both objects are equal, + * false otherwise. + */ + public boolean equals(Object obj) + { + if(! (obj instanceof CopiesDefault)) + return false; + + return super.equals(obj); + } + + /** + * Returns category of this class. + * + * @return The class CopiesDefault itself. + */ + public Class getCategory() + { + return CopiesDefault.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "copies-default". + */ + public String getName() + { + return "copies-default"; + } + + /** + * Returns the equally enum of the standard attribute class + * of this DefaultValuesAttribute enum. + *

    May return null if no value exists in JPS API.

    + * + * @return The enum of the standard attribute class. + */ + public Attribute getAssociatedAttribute() + { + return new Copies(getValue()); + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/DocumentFormatDefault.java b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/DocumentFormatDefault.java new file mode 100644 index 000000000..5eff91498 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/DocumentFormatDefault.java @@ -0,0 +1,106 @@ +/* DocumentFormatDefault.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.defaults; + +import gnu.javax.print.ipp.attribute.DefaultValueAttribute; +import gnu.javax.print.ipp.attribute.printer.DocumentFormat; + +import java.util.Locale; + +import javax.print.attribute.Attribute; +import javax.print.attribute.TextSyntax; + +/** + * DocumentFormatDefault specifies the default document + * format of a printer. + * + * @author Wolfgang Baer (WBaer@gmx.de) + * + */ +public final class DocumentFormatDefault extends TextSyntax + implements DefaultValueAttribute +{ + + /** + * Creates a DocumentFormatDefault object with the + * given value and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @exception NullPointerException if value is null + */ + public DocumentFormatDefault(String value, Locale locale) + { + super(value, locale); + } + + /** + * Returns category of this class. + * + * @return The class DocumentFormatDefault itself. + */ + public Class getCategory() + { + return DocumentFormatDefault.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "document-format-default". + */ + public String getName() + { + return "document-format-default"; + } + + /** + * Returns the equally enum of the standard attribute class + * of this DefaultValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public Attribute getAssociatedAttribute() + { + return new DocumentFormat(getValue(), getLocale()); + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/FinishingsDefault.java b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/FinishingsDefault.java new file mode 100644 index 000000000..9d4a06002 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/FinishingsDefault.java @@ -0,0 +1,263 @@ +/* FinishingsDefault.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.defaults; + +import gnu.javax.print.ipp.IppUtilities; +import gnu.javax.print.ipp.attribute.DefaultValueAttribute; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; + + +/** + * The FinishingsDefault attribute provides the supported + * values for finishings of a job. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class FinishingsDefault extends EnumSyntax + implements DefaultValueAttribute +{ + + /** No finishing. */ + public static final FinishingsDefault NONE = new FinishingsDefault(3); + + /** Staple the document(s) */ + public static final FinishingsDefault STAPLE = new FinishingsDefault(4); + + /** Cover a document */ + public static final FinishingsDefault COVER = new FinishingsDefault(6); + + /** + * This value indicates that a binding is to be applied to the document. + * The type and placement of the binding is site-defined. + */ + public static final FinishingsDefault BIND = new FinishingsDefault(7); + + /** + * Bind the document(s) with one or more staples (wire stitches) + * along the middle fold. + */ + public static final FinishingsDefault SADDLE_STITCH = new FinishingsDefault(8); + + /** + * Bind the document(s) with one or more staples (wire stitches) + * along one edge. + */ + public static final FinishingsDefault EDGE_STITCH = new FinishingsDefault(9); + + /** + * Bind the document(s) with one or more staples in the top left + * corner. + */ + public static final FinishingsDefault STAPLE_TOP_LEFT = new FinishingsDefault(20); + + /** + * Bind the document(s) with one or more staples in the bottom + * left corner. + */ + public static final FinishingsDefault STAPLE_BOTTOM_LEFT = new FinishingsDefault(21); + + /** + * Bind the document(s) with one or more staples in the top right corner. + */ + public static final FinishingsDefault STAPLE_TOP_RIGHT = new FinishingsDefault(22); + + /** + * Bind the document(s) with one or more staples in the bottom right corner. + */ + public static final FinishingsDefault STAPLE_BOTTOM_RIGHT = new FinishingsDefault(23); + + /** + * Bind the document(s) with one or more staples (wire stitches) + * along the left edge. + */ + public static final FinishingsDefault EDGE_STITCH_LEFT = new FinishingsDefault(24); + + /** + * Bind the document(s) with one or more staples (wire stitches) along + * the top edge. + */ + public static final FinishingsDefault EDGE_STITCH_TOP = new FinishingsDefault(25); + + /** + * Bind the document(s) with one or more staples (wire stitches) along + * the right edge. + */ + public static final FinishingsDefault EDGE_STITCH_RIGHT = new FinishingsDefault(26); + + /** + * Bind the document(s) with one or more staples (wire stitches) along + * the bottom edge. + */ + public static final FinishingsDefault EDGE_STITCH_BOTTOM = new FinishingsDefault(27); + + /** + * Bind the document(s) with two staples (wire stitches) along the + * left edge assuming a portrait document. + */ + public static final FinishingsDefault STAPLE_DUAL_LEFT = new FinishingsDefault(28); + + /** + * Bind the document(s) with two staples (wire stitches) along the + * top edge assuming a portrait document. + */ + public static final FinishingsDefault STAPLE_DUAL_TOP = new FinishingsDefault(29); + + /** + * Bind the document(s) with two staples (wire stitches) along the + * right edge assuming a portrait document. + */ + public static final FinishingsDefault STAPLE_DUAL_RIGHT = new FinishingsDefault(30); + + /** + * Bind the document(s) with two staples (wire stitches) along the + * bottom edge assuming a portrait document. + */ + public static final FinishingsDefault STAPLE_DUAL_BOTTOM = new FinishingsDefault(31); + + private static final String[] stringTable = { "none", "staple", null, + "cover", "bind", "saddle-stitch", + "edge-stitch", null, null, null, + null, null, null, null, null, + null, null, "staple-top-left", + "staple-bottom-left", + "staple-top-right", + "staple-bottom-right", + "edge-stitch-left", + "edge-stitch-top", + "edge-stitch-right", + "edge-stitch-bottom", + "staple-dual-left", + "staple-dual-top", + "staple-dual-right", + "staple-dual-bottom" }; + + private static final FinishingsDefault[] enumValueTable = { NONE, STAPLE, null, + COVER, BIND, + SADDLE_STITCH, + EDGE_STITCH, null, + null, null, null, + null, null, null, + null, null, null, + STAPLE_TOP_LEFT, + STAPLE_BOTTOM_LEFT, + STAPLE_TOP_RIGHT, + STAPLE_BOTTOM_RIGHT, + EDGE_STITCH_LEFT, + EDGE_STITCH_TOP, + EDGE_STITCH_RIGHT, + EDGE_STITCH_BOTTOM, + STAPLE_DUAL_LEFT, + STAPLE_DUAL_TOP, + STAPLE_DUAL_RIGHT, + STAPLE_DUAL_BOTTOM }; + + /** + * Constructs a FinishingsDefault object. + * + * @param value the value + */ + protected FinishingsDefault(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return the class FinishingsDefault itself + */ + public Class getCategory() + { + return FinishingsDefault.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "finishings-default". + */ + public String getName() + { + return "finishings-default"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } + + /** + * Returns the lowest used value by the enumerations of this class. + * . + * @return The lowest value used. + */ + protected int getOffset() + { + return 3; + } + + /** + * Returns the equally enum of the standard attribute class + * of this DefaultValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public Attribute getAssociatedAttribute() + { + return IppUtilities.getEnumAttribute("finishings", new Integer(getValue())); + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/JobHoldUntilDefault.java b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/JobHoldUntilDefault.java new file mode 100644 index 000000000..7c29f231c --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/JobHoldUntilDefault.java @@ -0,0 +1,149 @@ +/* JobHoldUntilDefault.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.defaults; + +import gnu.javax.print.ipp.attribute.DefaultValueAttribute; + +import java.util.Date; +import java.util.Locale; + +import javax.print.attribute.Attribute; +import javax.print.attribute.TextSyntax; +import javax.print.attribute.standard.JobHoldUntil; + +/** + * JobHoldUntilDefault attribute provides the default value + * for the attribute type job-hold-until. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class JobHoldUntilDefault extends TextSyntax + implements DefaultValueAttribute +{ + + // a keyword/name based attribute in IPP + // can be extended by administrators + // standard values are predefined + + /** Job should be printed immediately. */ + public static final JobHoldUntilDefault NO_HOLD = + new JobHoldUntilDefault("no-hold", null); + + /** Job should be hold indefinitely. */ + public static final JobHoldUntilDefault INDEFINITE = + new JobHoldUntilDefault("indefinite", null); + + /** Job should be processed during the day. */ + public static final JobHoldUntilDefault DAY_TIME = + new JobHoldUntilDefault("day-time", null); + + /** Job should be processed in the evening. */ + public static final JobHoldUntilDefault EVENING = + new JobHoldUntilDefault("evening", null); + + /** Job should be processed during night. */ + public static final JobHoldUntilDefault NIGHT = + new JobHoldUntilDefault("night", null); + + /** Job should be processed during the weekend. */ + public static final JobHoldUntilDefault WEEKEND = + new JobHoldUntilDefault("weekend", null); + + /** + * Job should be processed as second-shift + * (after close of business). + */ + public static final JobHoldUntilDefault SECOND_SHIFT = + new JobHoldUntilDefault("second-shift", null); + + /** + * Job should be processed as third-shift + * (after midnight). + */ + public static final JobHoldUntilDefault THIRD_SHIFT = + new JobHoldUntilDefault("third-shift", null); + + /** + * Creates a JobHoldUntilDefault object with the + * given value and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @throws NullPointerException if value is null + */ + public JobHoldUntilDefault(String value, Locale locale) + { + super(value, locale); + } + + /** + * Returns category of this class. + * + * @return The class JobHoldUntilDefault itself. + */ + public Class getCategory() + { + return JobHoldUntilDefault.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "job-hold-until-default". + */ + public String getName() + { + return "job-hold-until-default"; + } + + /** + * Returns the equally enum of the standard attribute class + * of this DefaultValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public Attribute getAssociatedAttribute() + { + // FIXME Same Mapping problem as in IppPrintService + return new JobHoldUntil(new Date()); + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/JobPriorityDefault.java b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/JobPriorityDefault.java new file mode 100644 index 000000000..9430250ae --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/JobPriorityDefault.java @@ -0,0 +1,118 @@ +/* JobPriorityDefault.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.print.ipp.attribute.defaults; + +import gnu.javax.print.ipp.attribute.DefaultValueAttribute; + +import javax.print.attribute.Attribute; +import javax.print.attribute.IntegerSyntax; +import javax.print.attribute.standard.JobPriority; + + +/** + * JobPriorityDefault attribute provides the default value of + * the printer object for the job-priority attribute. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class JobPriorityDefault extends IntegerSyntax + implements DefaultValueAttribute +{ + + /** + * Creates a JobPriorityDefault object. + * + * @param value the priority + * + * @exception IllegalArgumentException if value < 1 or value > 100 + */ + public JobPriorityDefault(int value) + { + super(value); + + if (value < 1 || value > 100) + throw new IllegalArgumentException("value out of range"); + } + + /** + * Tests if the given object is equal to this object. + * + * @param obj the object to test + * + * @return true if both objects are equal, + * false otherwise. + */ + public boolean equals(Object obj) + { + if(! (obj instanceof JobPriorityDefault)) + return false; + + return super.equals(obj); + } + + /** + * Returns category of this class. + * + * @return The class JobPriorityDefault itself. + */ + public Class getCategory() + { + return JobPriorityDefault.class; + } + + /** + * Returns name of this class. + * + * @return The anme "job-priority-default". + */ + public String getName() + { + return "job-priority-default"; + } + + /** + * Returns the equally enum of the standard attribute class + * of this DefaultValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public Attribute getAssociatedAttribute() + { + return new JobPriority(getValue()); + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/JobSheetsDefault.java b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/JobSheetsDefault.java new file mode 100644 index 000000000..6bf027eda --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/JobSheetsDefault.java @@ -0,0 +1,122 @@ +/* JobSheetsDefault.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.defaults; + +import gnu.javax.print.ipp.attribute.DefaultValueAttribute; + +import java.util.Locale; + +import javax.print.attribute.Attribute; +import javax.print.attribute.TextSyntax; +import javax.print.attribute.standard.JobSheets; + +/** + * JobSheetsDefault attribute provides the default value of + * the printer object for the job-sheets attribute. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class JobSheetsDefault extends TextSyntax + implements DefaultValueAttribute +{ + //a keyword/name based attribute in IPP + // can be extended by administrators + // standard values are predefined + + /** No job sheet is the default */ + public static final JobSheetsDefault NONE = + new JobSheetsDefault("none", Locale.getDefault()); + + /** A job sheet is the default */ + public static final JobSheetsDefault STANDARD = + new JobSheetsDefault("standard", Locale.getDefault()); + + /** + * Creates a JobSheetsDefault object with the + * given value and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @throws NullPointerException if value is null + */ + public JobSheetsDefault(String value, Locale locale) + { + super(value, locale); + } + + /** + * Returns category of this class. + * + * @return The class JobSheetsDefault itself. + */ + public Class getCategory() + { + return JobSheetsDefault.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "job-sheets-default". + */ + public String getName() + { + return "job-sheets-default"; + } + + /** + * Returns the equally enum of the standard attribute class + * of this DefaultValuesAttribute enum. + *

    May return null if no value exists in JPS API.

    + * + * @return The enum of the standard attribute class. + */ + public Attribute getAssociatedAttribute() + { + if (this.equals(JobSheetsDefault.NONE)) + return JobSheets.NONE; + if (this.equals(JobSheetsDefault.STANDARD)) + return JobSheets.STANDARD; + + return null; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/MediaDefault.java b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/MediaDefault.java new file mode 100644 index 000000000..5945d0b9b --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/MediaDefault.java @@ -0,0 +1,105 @@ +/* MediaDefault.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.defaults; + +import gnu.javax.print.ipp.IppUtilities; +import gnu.javax.print.ipp.attribute.DefaultValueAttribute; + +import java.util.Locale; + +import javax.print.attribute.Attribute; +import javax.print.attribute.TextSyntax; + +/** + * MediaDefault attribute provides the default value of + * the printer object for the media attribute. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class MediaDefault extends TextSyntax + implements DefaultValueAttribute +{ + + /** + * Creates a MediaDefault object with the + * given value and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @throws NullPointerException if value is null + */ + public MediaDefault(String value, Locale locale) + { + super(value, locale); + } + + /** + * Returns category of this class. + * + * @return The class MediaDefault itself. + */ + public Class getCategory() + { + return MediaDefault.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "media-default". + */ + public String getName() + { + return "media-default"; + } + + /** + * Returns the equally enum of the standard attribute class + * of this DefaultValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public Attribute getAssociatedAttribute() + { + return IppUtilities.getEnumAttribute("media" , getValue()); + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/MultipleDocumentHandlingDefault.java b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/MultipleDocumentHandlingDefault.java new file mode 100644 index 000000000..1563db82c --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/MultipleDocumentHandlingDefault.java @@ -0,0 +1,152 @@ +/* MultipleDocumentHandlingDefault.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.print.ipp.attribute.defaults; + +import gnu.javax.print.ipp.IppUtilities; +import gnu.javax.print.ipp.attribute.DefaultValueAttribute; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; + + +/** + * MultipleDocumentHandlingDefault provides the + * default value for the MultipleDocumentHandling attribute. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class MultipleDocumentHandlingDefault extends EnumSyntax + implements DefaultValueAttribute +{ + + //a keyword based attribute in IPP - int values just starting at 0 + + /** + * Supports only multiple documents treated as a single document. This + * applies to attributes which specify treatment of multiple document jobs. + */ + public static final MultipleDocumentHandlingDefault SINGLE_DOCUMENT = + new MultipleDocumentHandlingDefault(0); + + /** Supports multiple documents as uncollated copies */ + public static final MultipleDocumentHandlingDefault SEPARATE_DOCUMENTS_UNCOLLATED_COPIES = + new MultipleDocumentHandlingDefault(1); + + /** Supports multiple documents as collated copies */ + public static final MultipleDocumentHandlingDefault SEPARATE_DOCUMENTS_COLLATED_COPIES = + new MultipleDocumentHandlingDefault(2); + + /** + * Supports multiple documents where every single document starts + * with a new sheet. + */ + public static final MultipleDocumentHandlingDefault SINGLE_DOCUMENT_NEW_SHEET = + new MultipleDocumentHandlingDefault(3); + + private static final String[] stringTable = { "single-document", + "separate-documents-uncollated-copies", + "separate-documents-collated-copies", + "single-document-new-sheet" }; + + private static final MultipleDocumentHandlingDefault[] enumValueTable = + { SINGLE_DOCUMENT, SEPARATE_DOCUMENTS_UNCOLLATED_COPIES, + SEPARATE_DOCUMENTS_COLLATED_COPIES, SINGLE_DOCUMENT_NEW_SHEET}; + + /** + * Constructs a MultipleDocumentHandlingDefault object. + * + * @param value the enum value + */ + protected MultipleDocumentHandlingDefault(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class MultipleDocumentHandlingDefault itself. + */ + public Class getCategory() + { + return MultipleDocumentHandlingDefault.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "multiple-document-handling-default". + */ + public String getName() + { + return "multiple-document-handling-default"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } + + /** + * Returns the equally enum of the standard attribute class + * of this DefaultValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public Attribute getAssociatedAttribute() + { + return IppUtilities.getEnumAttribute("multiple-document-handling", + new Integer(getValue())); + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/NumberUpDefault.java b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/NumberUpDefault.java new file mode 100644 index 000000000..8e2d076d5 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/NumberUpDefault.java @@ -0,0 +1,114 @@ +/* NumberUpDefault.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.print.ipp.attribute.defaults; + +import gnu.javax.print.ipp.attribute.DefaultValueAttribute; + +import javax.print.attribute.Attribute; +import javax.print.attribute.IntegerSyntax; +import javax.print.attribute.standard.NumberUp; + +/** + * NumberUpDefault attribute provides the default value of + * the numper up attribute. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class NumberUpDefault extends IntegerSyntax + implements DefaultValueAttribute +{ + + /** + * Creates a NumberUpDefault object. + * + * @param value the value + * @throws IllegalArgumentException if value < 1 + */ + public NumberUpDefault(int value) + { + super(value); + } + + /** + * Tests if the given object is equal to this object. + * + * @param obj the object to test + * + * @return true if both objects are equal, + * false otherwise. + */ + public boolean equals(Object obj) + { + if(! (obj instanceof NumberUpDefault)) + return false; + + return super.equals(obj); + } + + /** + * Returns category of this class. + * + * @return The class NumberUpDefault itself. + */ + public Class getCategory() + { + return NumberUpDefault.class; + } + + /** + * Returns name of this class. + * + * @return The name "number-up-default". + */ + public String getName() + { + return "number-up-default"; + } + + /** + * Returns the equally enum of the standard attribute class + * of this DefaultValuesAttribute enum. + *

    May return null if no value exists in JPS API.

    + * + * @return The enum of the standard attribute class. + */ + public Attribute getAssociatedAttribute() + { + return new NumberUp(getValue()); + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/OrientationRequestedDefault.java b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/OrientationRequestedDefault.java new file mode 100644 index 000000000..4563ec525 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/OrientationRequestedDefault.java @@ -0,0 +1,154 @@ +/* OrientationRequestedDefault.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.print.ipp.attribute.defaults; + +import gnu.javax.print.ipp.IppUtilities; +import gnu.javax.print.ipp.attribute.DefaultValueAttribute; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; + + +/** + * The OrientationRequestedDefault attribute provides + * the default value for the job attribute orientation-requested. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class OrientationRequestedDefault extends EnumSyntax + implements DefaultValueAttribute +{ + + /** Orientation as portrait. */ + public static final OrientationRequestedDefault PORTRAIT = + new OrientationRequestedDefault(3); + + /** Orientation as landscape. */ + public static final OrientationRequestedDefault LANDSCAPE = + new OrientationRequestedDefault(4); + + /** Orientation as reversed landscape. */ + public static final OrientationRequestedDefault REVERSE_LANDSCAPE = + new OrientationRequestedDefault(5); + + /** Orientation as reversed portrait. */ + public static final OrientationRequestedDefault REVERSE_PORTRAIT = + new OrientationRequestedDefault(6); + + + private static final String[] stringTable = { "portrait", "landscape", + "reverse-landscape", + "reverse-portrait" }; + + private static final OrientationRequestedDefault[] + enumValueTable = { PORTRAIT, LANDSCAPE, + REVERSE_LANDSCAPE, REVERSE_PORTRAIT }; + + /** + * Constructs a OrientationRequestedDefault object. + * + * @param value the value + */ + protected OrientationRequestedDefault(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class OrientationRequestedDefault itself. + */ + public Class getCategory() + { + return OrientationRequestedDefault.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "orientation-requested-default". + */ + public String getName() + { + return "orientation-requested-default"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } + + /** + * Returns the lowest used value by the enumerations of this class. + * . + * @return The lowest value used. + */ + protected int getOffset() + { + return 3; + } + + /** + * Returns the equally enum of the standard attribute class + * of this DefaultValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public Attribute getAssociatedAttribute() + { + return IppUtilities.getEnumAttribute("orientation-requested", + new Integer(getValue())); + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/PrintQualityDefault.java b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/PrintQualityDefault.java new file mode 100644 index 000000000..7b123eeb4 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/PrintQualityDefault.java @@ -0,0 +1,141 @@ +/* PrintQualityDefault.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.print.ipp.attribute.defaults; + +import gnu.javax.print.ipp.IppUtilities; +import gnu.javax.print.ipp.attribute.DefaultValueAttribute; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; + + +/** + * PrintQualityDefault provides the + * default value for the print-quality attribute. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class PrintQualityDefault extends EnumSyntax + implements DefaultValueAttribute +{ + /** Draft quality of the printer. */ + public static final PrintQualityDefault DRAFT = new PrintQualityDefault(3); + + /** Normal quality of the printer. */ + public static final PrintQualityDefault NORMAL = new PrintQualityDefault(4); + + /** High quality of the printer. */ + public static final PrintQualityDefault HIGH = new PrintQualityDefault(5); + + private static final String[] stringTable = { "draft", "normal", "high" }; + + private static final PrintQualityDefault[] enumValueTable = { DRAFT, NORMAL, HIGH }; + + /** + * Constructs a PrintQualityDefault object. + * + * @param value the value of the enum + */ + protected PrintQualityDefault(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class PrintQualityDefault itself. + */ + public Class getCategory() + { + return PrintQualityDefault.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "print-quality-default". + */ + public String getName() + { + return "print-quality-default"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } + + /** + * Returns the lowest used value by the enumerations of this class. + * . + * @return The lowest value used. + */ + protected int getOffset() + { + return 3; + } + + /** + * Returns the equally enum of the standard attribute class + * of this DefaultValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public Attribute getAssociatedAttribute() + { + return IppUtilities.getEnumAttribute( + "print-quality", new Integer(getValue())); + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/PrinterResolutionDefault.java b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/PrinterResolutionDefault.java new file mode 100644 index 000000000..2c84b99ba --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/PrinterResolutionDefault.java @@ -0,0 +1,119 @@ +/* PrinterResolutionDefault.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.print.ipp.attribute.defaults; + +import gnu.javax.print.ipp.attribute.DefaultValueAttribute; + +import javax.print.attribute.Attribute; +import javax.print.attribute.ResolutionSyntax; +import javax.print.attribute.standard.PrinterResolution; + + +/** + * The PrinterResolutionDefault attribute provides + * the default value for the job attribute printer-resolution. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class PrinterResolutionDefault extends ResolutionSyntax + implements DefaultValueAttribute +{ + + /** + * Creates a ResolutionSyntax object with the given arguments. + * + * @param crossFeedResolution the cross feed resolution + * @param feedResolution the feed resolution + * @param units the unit to use (e.g. {@link #DPCM} or {@link #DPI}) + * + * @exception IllegalArgumentException if preconditions fail + */ + public PrinterResolutionDefault(int crossFeedResolution, int feedResolution, + int units) + { + super(crossFeedResolution, feedResolution, units); + } + + /** + * Tests if the given object is equal to this object. + * + * @param obj the object to test + * + * @return true if both objects are equal, + * false otherwise. + */ + public boolean equals(Object obj) + { + if(! (obj instanceof PrinterResolutionDefault)) + return false; + + return super.equals(obj); + } + + /** + * Returns category of this class. + * + * @return The class PrinterResolutionDefault itself. + */ + public Class getCategory() + { + return PrinterResolutionDefault.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "printer-resolution-default". + */ + public String getName() + { + return "printer-resolution-default"; + } + + /** + * Returns the equally enum of the standard attribute class + * of this DefaultValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public Attribute getAssociatedAttribute() + { + return new PrinterResolution(getCrossFeedResolutionDphi(), + getFeedResolutionDphi(), 1); + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/SidesDefault.java b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/SidesDefault.java new file mode 100644 index 000000000..a50560ae9 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/SidesDefault.java @@ -0,0 +1,150 @@ +/* SidesDefault.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.print.ipp.attribute.defaults; + +import gnu.javax.print.ipp.IppUtilities; +import gnu.javax.print.ipp.attribute.DefaultValueAttribute; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; + + +/** + * SidesDefault provides the + * default for the sides attribute. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class SidesDefault extends EnumSyntax + implements DefaultValueAttribute +{ + + /** Specifies that each page should be printed on one sheet. */ + public static final SidesDefault ONE_SIDED = new SidesDefault(0); + + /** + * Specifies that two following pages should be printed on the + * front and back of one sheet for binding on the long edge. + */ + public static final SidesDefault TWO_SIDED_LONG_EDGE = + new SidesDefault(1); + + /** + * Specifies that two following pages should be printed on the + * front and back of one sheet for binding on the short edge. + */ + public static final SidesDefault TWO_SIDED_SHORT_EDGE = + new SidesDefault(2); + + /** An alias constant for "two sided long edge". */ + public static final SidesDefault DUPLEX = new SidesDefault(1); + + /** An alias constant for "two sided short edge". */ + public static final SidesDefault TUMBLE = new SidesDefault(2); + + private static final String[] stringTable = { "one-sided", + "two-sided-long-edge", + "two-sided-short-edge" }; + + private static final SidesDefault[] enumValueTable = { ONE_SIDED, + TWO_SIDED_LONG_EDGE, + TWO_SIDED_SHORT_EDGE }; + + + /** + * Creates a SidesDefault object. + * + * @param value the value of the enum + */ + protected SidesDefault(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class SidesDefault itself. + */ + public Class getCategory() + { + return SidesDefault.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "sides-default". + */ + public String getName() + { + return "sides-default"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } + + /** + * Returns the equally enum of the standard attribute class + * of this DefaultValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public Attribute getAssociatedAttribute() + { + return IppUtilities.getEnumAttribute("sides", new Integer(getValue())); + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/job/AttributesCharset.java b/libjava/classpath/gnu/javax/print/ipp/attribute/job/AttributesCharset.java new file mode 100644 index 000000000..4fe2ce0d5 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/job/AttributesCharset.java @@ -0,0 +1,93 @@ +/* AttributesCharset.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.job; + +import gnu.javax.print.ipp.attribute.CharsetSyntax; + +import javax.print.attribute.Attribute; + +/** + * AttributesCharset attribute as described in RFC 2911 chapter + * 3.1.4 Character Set and Natural Language Operation Attributes. + *

    + * This operation attribute identifies the charset used by any text + * and name attribute supplied by the client in the request. This + * charset must be used by the printer object in the response.
    + * All clients and IPP objects must support the 'utf-8' charset. + *

    + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class AttributesCharset extends CharsetSyntax + implements Attribute +{ + + /** Defines a default UTF-8 charset instance */ + public static final AttributesCharset UTF8 = new AttributesCharset("utf-8"); + + /** + * Creates a AttributesCharset object. + * + * @param value the charset string value. + */ + public AttributesCharset(String value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class AttributesCharset itself. + */ + public Class getCategory() + { + return AttributesCharset.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "attributes-charset". + */ + public String getName() + { + return "attributes-charset"; + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/job/AttributesNaturalLanguage.java b/libjava/classpath/gnu/javax/print/ipp/attribute/job/AttributesNaturalLanguage.java new file mode 100644 index 000000000..151cec439 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/job/AttributesNaturalLanguage.java @@ -0,0 +1,95 @@ +/* AttributesNaturalLanguage.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.job; + + +import gnu.javax.print.ipp.attribute.NaturalLanguageSyntax; + +import javax.print.attribute.Attribute; + +/** + * AttributesNaturalLanguage attribute as described in RFC 2911 chapter + * 3.1.4 Character Set and Natural Language Operation Attributes. + *

    + * This operation attribute identifies the natural language used + * by any text and name attribute supplied by the client in the request. + * The printer object should use this natural language for the response + * to this request. + *

    + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class AttributesNaturalLanguage extends NaturalLanguageSyntax + implements Attribute +{ + + /** Defines the default language EN */ + public static final AttributesNaturalLanguage EN = + new AttributesNaturalLanguage("en"); + + /** + * Creates a AttributesNaturalLanguage object. + * + * @param value the language string value. + */ + public AttributesNaturalLanguage(String value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class AttributesNaturalLanguage itself. + */ + public Class getCategory() + { + return AttributesNaturalLanguage.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "attributes-natural-language". + */ + public String getName() + { + return "attributes-natural-language"; + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobDetailedStatusMessages.java b/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobDetailedStatusMessages.java new file mode 100644 index 000000000..5b83344a9 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobDetailedStatusMessages.java @@ -0,0 +1,92 @@ +/* JobDetailedStatusMessages.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.job; + +import java.util.Locale; + +import javax.print.attribute.Attribute; +import javax.print.attribute.TextSyntax; + +/** + * JobDetailedStatusMessages provides additional detailed and + * technical job informations. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class JobDetailedStatusMessages + extends TextSyntax implements Attribute +{ + + /** + * Creates a JobDetailedStatusMessages object with the given value + * and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @exception NullPointerException if value is null + */ + public JobDetailedStatusMessages(String value, Locale locale) + { + super(value, locale); + } + + /** + * Returns category of this class. + * + * @return The class JobDetailedStatusMessages itself. + */ + public Class getCategory() + { + return JobDetailedStatusMessages.class; + } + + + /** + * Returns the name of this attribute. + * + * @return The name "job-detailed-status-messages". + */ + public String getName() + { + return "job-detailed-status-messages"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobDocumentAccessErrors.java b/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobDocumentAccessErrors.java new file mode 100644 index 000000000..c3fff057c --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobDocumentAccessErrors.java @@ -0,0 +1,93 @@ +/* JobDocumentAccessErrors.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.job; + +import java.util.Locale; + +import javax.print.attribute.Attribute; +import javax.print.attribute.TextSyntax; + +/** + * JobDocumentAccessErrors provides additional information + * for each access error for print-uri or document-uri jobs. + * technical job informations. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class JobDocumentAccessErrors + extends TextSyntax implements Attribute +{ + + /** + * Creates a JobDocumentAccessErrors object with the given value + * and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @exception NullPointerException if value is null + */ + public JobDocumentAccessErrors(String value, Locale locale) + { + super(value, locale); + } + + /** + * Returns category of this class. + * + * @return The class JobDocumentAccessErrors itself. + */ + public Class getCategory() + { + return JobDocumentAccessErrors.class; + } + + + /** + * Returns the name of this attribute. + * + * @return The name "job-document-access-errors". + */ + public String getName() + { + return "job-document-access-errors"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobId.java b/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobId.java new file mode 100644 index 000000000..78c866723 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobId.java @@ -0,0 +1,87 @@ +/* JobId.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.job; + +import javax.print.attribute.Attribute; +import javax.print.attribute.IntegerSyntax; + +/** + * The JobId attribute contains the ID of a + * print job created or currently being processed. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class JobId extends IntegerSyntax implements Attribute +{ + + /** + * Creates a IntegerSyntax with the given value. + * + * @param value the integer to set + * @throws IllegalArgumentException if value is < 1 + */ + public JobId(int value) + { + super(value); + + if (value < 1) + throw new IllegalArgumentException("job-id may not be less than 1"); + } + + /** + * Returns category of this class. + * + * @return The class JobId itself. + */ + public Class getCategory() + { + return JobId.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "job-id". + */ + public String getName() + { + return "job-id"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobMoreInfo.java b/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobMoreInfo.java new file mode 100644 index 000000000..569400f40 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobMoreInfo.java @@ -0,0 +1,87 @@ +/* JobMoreInfo.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.job; + +import java.net.URI; + +import javax.print.attribute.Attribute; +import javax.print.attribute.URISyntax; + +/** + * JobMoreInfo attribute as described in RFC 2911 section + * 4.3.4 contains the URI where more information about a job + * (e.g. through a HTML page) can be found. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class JobMoreInfo extends URISyntax implements Attribute +{ + + /** + * Creates a JobMoreInfo object. + * + * @param uri the URI value for the syntax + * @throws NullPointerException if uri is null + */ + public JobMoreInfo(URI uri) + { + super(uri); + } + + /** + * Returns category of this class. + * + * @return The class JobMoreInfo itself. + */ + public Class getCategory() + { + return JobMoreInfo.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "job-more-info". + */ + public String getName() + { + return "job-more-info"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobPrinterUri.java b/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobPrinterUri.java new file mode 100644 index 000000000..1375a2419 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobPrinterUri.java @@ -0,0 +1,87 @@ +/* JobPrinterUri.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.job; + +import java.net.URI; + +import javax.print.attribute.Attribute; +import javax.print.attribute.URISyntax; + +/** + * JobPrinterUri attribute as described in RFC 2911 section + * 4.3.3 contains the URI of the printer which created and + * processes a job. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class JobPrinterUri extends URISyntax implements Attribute +{ + + /** + * Creates a JobPrinterUri object. + * + * @param uri the URI value for the syntax + * @throws NullPointerException if uri is null + */ + public JobPrinterUri(URI uri) + { + super(uri); + } + + /** + * Returns category of this class. + * + * @return The class JobPrinterUri itself. + */ + public Class getCategory() + { + return JobPrinterUri.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "job-printer-uri". + */ + public String getName() + { + return "job-printer-uri"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobStateMessage.java b/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobStateMessage.java new file mode 100644 index 000000000..d65126621 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobStateMessage.java @@ -0,0 +1,92 @@ +/* JobStateMessage.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.job; + +import java.util.Locale; + +import javax.print.attribute.Attribute; +import javax.print.attribute.TextSyntax; + +/** + * JobStateMessage attribute describes information about the + * job-state and job-state-reasons in human readable form. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class JobStateMessage + extends TextSyntax implements Attribute +{ + + /** + * Creates a JobStateMessage object with the given value + * and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @exception NullPointerException if value is null + */ + public JobStateMessage(String value, Locale locale) + { + super(value, locale); + } + + /** + * Returns category of this class. + * + * @return The class JobStateMessage itself. + */ + public Class getCategory() + { + return JobStateMessage.class; + } + + + /** + * Returns the name of this attribute. + * + * @return The name "job-state-message". + */ + public String getName() + { + return "job-state-message"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobUri.java b/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobUri.java new file mode 100644 index 000000000..4b545b956 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobUri.java @@ -0,0 +1,87 @@ +/* JobUri.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.job; + +import java.net.URI; + +import javax.print.attribute.Attribute; +import javax.print.attribute.URISyntax; + +/** + * JobUri attribute as described in RFC 2911 section + * 4.3.1 contains the URI for a job generated by the printer + * after a create request. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class JobUri extends URISyntax implements Attribute +{ + + /** + * Creates a JobUri object. + * + * @param uri the URI value for the syntax + * @throws NullPointerException if uri is null + */ + public JobUri(URI uri) + { + super(uri); + } + + /** + * Returns category of this class. + * + * @return The class JobUri itself. + */ + public Class getCategory() + { + return JobUri.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "job-uri". + */ + public String getName() + { + return "job-uri"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/printer/CharsetConfigured.java b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/CharsetConfigured.java new file mode 100644 index 000000000..42430377c --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/CharsetConfigured.java @@ -0,0 +1,86 @@ +/* CharsetConfigured.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.printer; + +import gnu.javax.print.ipp.attribute.CharsetSyntax; + +import javax.print.attribute.Attribute; + +/** + * CharsetConfigured attribute as described in RFC 2911 section + * 4.4.17 provides the charset which is configured by the + * server to be used in the name and text syntax attribute types. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class CharsetConfigured extends CharsetSyntax + implements Attribute +{ + + /** + * Creates a CharsetConfigured object. + * + * @param value the charset string value. + */ + public CharsetConfigured(String value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class CharsetConfigured itself. + */ + public Class getCategory() + { + return CharsetConfigured.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "charset-configured". + */ + public String getName() + { + return "charset-configured"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/printer/DocumentFormat.java b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/DocumentFormat.java new file mode 100644 index 000000000..9a5e01e1d --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/DocumentFormat.java @@ -0,0 +1,111 @@ +/* DocumentFormat.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.printer; + +import java.util.Locale; + +import javax.print.DocFlavor; +import javax.print.attribute.Attribute; +import javax.print.attribute.SupportedValuesAttribute; +import javax.print.attribute.TextSyntax; + +/** + * DocumentFormatSupported specifies the supported document + * formats of a printer. Printer are supplying a set of this attribute. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class DocumentFormat extends TextSyntax + implements SupportedValuesAttribute +{ + + /** + * Creates a DocumentFormat object with the + * given value and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @exception NullPointerException if value is null + */ + public DocumentFormat(String value, Locale locale) + { + super(value, locale); + } + + /** + * Constructs a document format object for the given flavor. + * The constructor reworkes the mimetype of the given flavor + * to remove the quoted charset parameter if present. + * + * @param flavor the flavor with the mimetype + * @return The created document format. + */ + public static DocumentFormat createDocumentFormat(DocFlavor flavor) + { + String charset = flavor.getParameter("charset"); + String mimetype = flavor.getMediaType() + "/" + flavor.getMediaSubtype(); + if (charset != null) + mimetype += "; charset=" + charset; + + return new DocumentFormat(mimetype, null); + } + + /** + * Returns category of this class. + * + * @return The class DocumentFormat itself. + */ + public Class getCategory() + { + return DocumentFormat.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "document-format". + */ + public String getName() + { + return "document-format"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/printer/MultipleOperationTimeOut.java b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/MultipleOperationTimeOut.java new file mode 100644 index 000000000..bb00b8891 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/MultipleOperationTimeOut.java @@ -0,0 +1,86 @@ +/* MultipleOperationTimeOut.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.printer; + +import javax.print.attribute.Attribute; +import javax.print.attribute.IntegerSyntax; + +/** + * MultipleOperationTimeOut attribute as described in RFC 2911 section + * 4.4.31 provides the minimum time ins second a printer object waits + * before time out and recovery. The printer object waits e.g. for + * additional SendDocument or SendUri operations. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class MultipleOperationTimeOut extends IntegerSyntax + implements Attribute +{ + + /** + * Creates a MultipleOperationTimeOut with the given value. + * + * @param value the integer to set + */ + public MultipleOperationTimeOut(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class MultipleOperationTimeOut itself. + */ + public Class getCategory() + { + return MultipleOperationTimeOut.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "multiple-operation-time-out". + */ + public String getName() + { + return "multiple-operation-time-out"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/printer/NaturalLanguageConfigured.java b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/NaturalLanguageConfigured.java new file mode 100644 index 000000000..8dc05fe58 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/NaturalLanguageConfigured.java @@ -0,0 +1,86 @@ +/* NaturalLanguageConfigured.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.printer; + +import gnu.javax.print.ipp.attribute.NaturalLanguageSyntax; + +import javax.print.attribute.Attribute; + +/** + * NaturalLanguageConfigured attribute as described in RFC 2911 + * section 4.4.19 provides the natural language which is configured + * by the server to be used in the name and text syntax attribute types. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class NaturalLanguageConfigured extends NaturalLanguageSyntax + implements Attribute +{ + + /** + * Creates a NaturalLanguageConfigured object. + * + * @param value the charset string value. + */ + public NaturalLanguageConfigured(String value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class NaturalLanguageConfigured itself. + */ + public Class getCategory() + { + return NaturalLanguageConfigured.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "natural-language-configured". + */ + public String getName() + { + return "natural-language-configured"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterCurrentTime.java b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterCurrentTime.java new file mode 100644 index 000000000..361916773 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterCurrentTime.java @@ -0,0 +1,107 @@ +/* PrinterCurrentTime.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.printer; + +import java.util.Date; + +import javax.print.attribute.Attribute; +import javax.print.attribute.DateTimeSyntax; +import javax.print.attribute.PrintServiceAttribute; + +/** + * PrinterCurrentTime attribute as described in RFC 2911 section + * 4.4.30 provides the current time of the print service. + * Its to be used by other attributes like the date-time-at-xxx + * attributes in the creation process. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class PrinterCurrentTime extends DateTimeSyntax + implements PrintServiceAttribute +{ + + /** + * Creates a PrinterCurrentTime object. + * + * @param value the date at creation time + * + * @exception NullPointerException if value is null + */ + public PrinterCurrentTime(Date value) + { + super(value); + } + + /** + * Tests if the given object is equal to this object. + * + * @param obj the object to test + * + * @return true if both objects are equal, + * false otherwise. + */ + public boolean equals(Object obj) + { + if(! (obj instanceof PrinterCurrentTime)) + return false; + + return super.equals(obj); + } + + /** + * Returns category of this class. + * + * @return The class PrinterCurrentTime itself. + */ + public Class getCategory() + { + return PrinterCurrentTime.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "printer-current-time". + */ + public String getName() + { + return "printer-current-time"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterDriverInstaller.java b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterDriverInstaller.java new file mode 100644 index 000000000..28a2f4485 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterDriverInstaller.java @@ -0,0 +1,88 @@ +/* PrinterDriverInstaller.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.printer; + +import java.net.URI; + +import javax.print.attribute.Attribute; +import javax.print.attribute.URISyntax; + +/** + * PrinterDriverInstaller attribute as described in RFC 2911 section + * 4.4.81 provides the URI where a printer driver installer + * can be found. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class PrinterDriverInstaller extends URISyntax + implements Attribute +{ + + /** + * Creates a PrinterDriverInstaller object. + * + * @param uri the URI value for the syntax + * @throws NullPointerException if uri is null + */ + public PrinterDriverInstaller(URI uri) + { + super(uri); + } + + /** + * Returns category of this class. + * + * @return The class PrinterDriverInstaller itself. + */ + public Class getCategory() + { + return PrinterDriverInstaller.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "printer-driver-installer". + */ + public String getName() + { + return "printer-driver-installer"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterStateMessage.java b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterStateMessage.java new file mode 100644 index 000000000..07c458889 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterStateMessage.java @@ -0,0 +1,94 @@ +/* PrinterStateMessage.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.printer; + +import java.util.Locale; + +import javax.print.attribute.Attribute; +import javax.print.attribute.PrintServiceAttribute; +import javax.print.attribute.TextSyntax; + +/** + * PrinterStateMessage attribute as described in RFC 2911 section + * 4.4.13 provides a textual representation of the attributes + * printer-state and printer-state-reasons for consumption by + * humans. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class PrinterStateMessage extends TextSyntax + implements PrintServiceAttribute +{ + + /** + * Creates a PrinterStateMessage object with the + * given value and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @exception NullPointerException if value is null + */ + public PrinterStateMessage(String value, Locale locale) + { + super(value, locale); + } + + /** + * Returns category of this class. + * + * @return The class PrinterStateMessage itself. + */ + public Class getCategory() + { + return PrinterStateMessage.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "printer-state-message". + */ + public String getName() + { + return "printer-state-message"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterUpTime.java b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterUpTime.java new file mode 100644 index 000000000..7bec92ed3 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterUpTime.java @@ -0,0 +1,86 @@ +/* PrinterUpTime.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.printer; + +import javax.print.attribute.Attribute; +import javax.print.attribute.IntegerSyntax; + +/** + * PrinterUpTime attribute as described in RFC 2911 section + * 4.4.29 provides the uptime of the printer object. This + * is a value in second starting at 1 after a initialization + * or reboot of the printer object. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class PrinterUpTime extends IntegerSyntax + implements Attribute +{ + + /** + * Creates a PrinterUpTime with the given value. + * + * @param value the integer to set + */ + public PrinterUpTime(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class PrinterUpTime itself. + */ + public Class getCategory() + { + return PrinterUpTime.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "printer-up-time". + */ + public String getName() + { + return "printer-up-time"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/CharsetSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/CharsetSupported.java new file mode 100644 index 000000000..22b484ef8 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/CharsetSupported.java @@ -0,0 +1,88 @@ +/* CharsetSupported.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.supported; + +import gnu.javax.print.ipp.attribute.CharsetSyntax; + +import javax.print.attribute.Attribute; +import javax.print.attribute.SupportedValuesAttribute; + +/** + * CharsetSupported attribute as described in RFC 2911 section + * 4.4.18 provides the charset which are supported by the + * IPP implementation to be used in the name and text syntax + * attribute types. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class CharsetSupported extends CharsetSyntax + implements SupportedValuesAttribute +{ + + /** + * Creates a CharsetSupported object. + * + * @param value the charset string value. + */ + public CharsetSupported(String value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class CharsetSupported itself. + */ + public Class getCategory() + { + return CharsetSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "charset-supported". + */ + public String getName() + { + return "charset-supported"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/CompressionSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/CompressionSupported.java new file mode 100644 index 000000000..768091cb2 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/CompressionSupported.java @@ -0,0 +1,161 @@ +/* CompressionSupported.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.print.ipp.attribute.supported; + +import gnu.javax.print.ipp.IppUtilities; + +import java.util.Iterator; +import java.util.Set; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; +import javax.print.attribute.SupportedValuesAttribute; +import javax.print.attribute.standard.Compression; + + +/** + * CompressionSupported provides the values which are + * supported for the compression attribute. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class CompressionSupported extends EnumSyntax + implements SupportedValuesAttribute +{ + + /** The print data is not compressed. */ + public static final CompressionSupported NONE = new CompressionSupported(0); + + /** The print data is ZIP compressed. */ + public static final CompressionSupported DEFLATE = new CompressionSupported(1); + + /** The print data is GNU Zip compressed. */ + public static final CompressionSupported GZIP = new CompressionSupported(2); + + /** The print data is UNIX compressed. */ + public static final CompressionSupported COMPRESS = new CompressionSupported(3); + + private static final String[] stringTable = { "none", "deflate", + "gzip", "compress" }; + + private static final CompressionSupported[] enumValueTable = { NONE, DEFLATE, + GZIP, COMPRESS }; + + /** + * Constructs a CompressionSupported object. + * + * @param value the enum value + */ + protected CompressionSupported(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class CompressionSupported itself. + */ + public Class getCategory() + { + return CompressionSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "compression-supported". + */ + public String getName() + { + return "compression-supported"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } + + /** + * Returns the equally enum of the standard attribute class + * of this SupportedValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public Compression getAssociatedAttribute() + { + return (Compression) IppUtilities.getEnumAttribute( + "compression", new Integer(getValue())); + } + + /** + * Constructs an array from a set of -supported attributes. + * @param set set to process + * @return The constructed array. + * + * @see #getAssociatedAttribute() + */ + public static Compression[] + getAssociatedAttributeArray(Set set) + { + Compression[] result = new Compression[set.size()]; + int j = 0; + for (Attribute tmp : set) + { + result[j] = ((CompressionSupported) tmp).getAssociatedAttribute(); + j++; + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/DocumentFormatSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/DocumentFormatSupported.java new file mode 100644 index 000000000..03449fa4f --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/DocumentFormatSupported.java @@ -0,0 +1,92 @@ +/* DocumentFormatSupported.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.supported; + +import java.util.Locale; + +import javax.print.attribute.Attribute; +import javax.print.attribute.SupportedValuesAttribute; +import javax.print.attribute.TextSyntax; + +/** + * DocumentFormatSupported specifies the supported document + * formats of a printer. Printer are supplying a set of this attribute. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class DocumentFormatSupported extends TextSyntax + implements SupportedValuesAttribute +{ + + /** + * Creates a DocumentFormatSupported object with the + * given value and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @exception NullPointerException if value is null + */ + public DocumentFormatSupported(String value, Locale locale) + { + super(value, locale); + } + + /** + * Returns category of this class. + * + * @return The class DocumentFormatSupported itself. + */ + public Class getCategory() + { + return DocumentFormatSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "document-format-supported". + */ + public String getName() + { + return "document-format-supported"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/FinishingsSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/FinishingsSupported.java new file mode 100644 index 000000000..f271fa71b --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/FinishingsSupported.java @@ -0,0 +1,302 @@ +/* FinishingsSupported.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.supported; + +import gnu.javax.print.ipp.IppUtilities; + +import java.util.Iterator; +import java.util.Set; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; +import javax.print.attribute.SupportedValuesAttribute; +import javax.print.attribute.standard.Finishings; + + +/** + * The FinishingsSupported attribute provides the supported + * values for finishings of a job. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class FinishingsSupported extends EnumSyntax + implements SupportedValuesAttribute +{ + + /** No finishing. */ + public static final FinishingsSupported NONE = new FinishingsSupported(3); + + /** Staple the document(s) */ + public static final FinishingsSupported STAPLE = new FinishingsSupported(4); + + /** Cover a document */ + public static final FinishingsSupported COVER = new FinishingsSupported(6); + + /** + * This value indicates that a binding is to be applied to the document. + * The type and placement of the binding is site-defined. + */ + public static final FinishingsSupported BIND = new FinishingsSupported(7); + + /** + * Bind the document(s) with one or more staples (wire stitches) + * along the middle fold. + */ + public static final FinishingsSupported SADDLE_STITCH = + new FinishingsSupported(8); + + /** + * Bind the document(s) with one or more staples (wire stitches) + * along one edge. + */ + public static final FinishingsSupported EDGE_STITCH = + new FinishingsSupported(9); + + /** + * Bind the document(s) with one or more staples in the top left + * corner. + */ + public static final FinishingsSupported STAPLE_TOP_LEFT = + new FinishingsSupported(20); + + /** + * Bind the document(s) with one or more staples in the bottom + * left corner. + */ + public static final FinishingsSupported STAPLE_BOTTOM_LEFT = + new FinishingsSupported(21); + + /** + * Bind the document(s) with one or more staples in the top right corner. + */ + public static final FinishingsSupported STAPLE_TOP_RIGHT = + new FinishingsSupported(22); + + /** + * Bind the document(s) with one or more staples in the bottom right corner. + */ + public static final FinishingsSupported STAPLE_BOTTOM_RIGHT = + new FinishingsSupported(23); + + /** + * Bind the document(s) with one or more staples (wire stitches) + * along the left edge. + */ + public static final FinishingsSupported EDGE_STITCH_LEFT = + new FinishingsSupported(24); + + /** + * Bind the document(s) with one or more staples (wire stitches) along + * the top edge. + */ + public static final FinishingsSupported EDGE_STITCH_TOP = + new FinishingsSupported(25); + + /** + * Bind the document(s) with one or more staples (wire stitches) along + * the right edge. + */ + public static final FinishingsSupported EDGE_STITCH_RIGHT = + new FinishingsSupported(26); + + /** + * Bind the document(s) with one or more staples (wire stitches) along + * the bottom edge. + */ + public static final FinishingsSupported EDGE_STITCH_BOTTOM = + new FinishingsSupported(27); + + /** + * Bind the document(s) with two staples (wire stitches) along the + * left edge assuming a portrait document. + */ + public static final FinishingsSupported STAPLE_DUAL_LEFT = + new FinishingsSupported(28); + + /** + * Bind the document(s) with two staples (wire stitches) along the + * top edge assuming a portrait document. + */ + public static final FinishingsSupported STAPLE_DUAL_TOP = + new FinishingsSupported(29); + + /** + * Bind the document(s) with two staples (wire stitches) along the + * right edge assuming a portrait document. + */ + public static final FinishingsSupported STAPLE_DUAL_RIGHT = + new FinishingsSupported(30); + + /** + * Bind the document(s) with two staples (wire stitches) along the + * bottom edge assuming a portrait document. + */ + public static final FinishingsSupported STAPLE_DUAL_BOTTOM = + new FinishingsSupported(31); + + private static final String[] stringTable = { "none", "staple", null, + "cover", "bind", "saddle-stitch", + "edge-stitch", null, null, null, + null, null, null, null, null, + null, null, "staple-top-left", + "staple-bottom-left", + "staple-top-right", + "staple-bottom-right", + "edge-stitch-left", + "edge-stitch-top", + "edge-stitch-right", + "edge-stitch-bottom", + "staple-dual-left", + "staple-dual-top", + "staple-dual-right", + "staple-dual-bottom" }; + + private static final FinishingsSupported[] enumValueTable = { NONE, STAPLE, + null, COVER, BIND, + SADDLE_STITCH, + EDGE_STITCH, null, + null, null, null, + null, null, null, + null, null, null, + STAPLE_TOP_LEFT, + STAPLE_BOTTOM_LEFT, + STAPLE_TOP_RIGHT, + STAPLE_BOTTOM_RIGHT, + EDGE_STITCH_LEFT, + EDGE_STITCH_TOP, + EDGE_STITCH_RIGHT, + EDGE_STITCH_BOTTOM, + STAPLE_DUAL_LEFT, + STAPLE_DUAL_TOP, + STAPLE_DUAL_RIGHT, + STAPLE_DUAL_BOTTOM }; + + /** + * Constructs a FinishingsSupported object. + * + * @param value the value + */ + protected FinishingsSupported(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return the class FinishingsSupported itself + */ + public Class getCategory() + { + return FinishingsSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "finishings-supported". + */ + public String getName() + { + return "finishings-supported"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } + + /** + * Returns the lowest used value by the enumerations of this class. + * . + * @return The lowest value used. + */ + protected int getOffset() + { + return 3; + } + + /** + * Returns the equally enum of the standard attribute class + * of this SupportedValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public Finishings getAssociatedAttribute() + { + return (Finishings) IppUtilities.getEnumAttribute( + "finishings", new Integer(getValue())); + } + + /** + * Constructs an array from a set of -supported attributes. + * @param set set to process + * @return The constructed array. + * + * @see #getAssociatedAttribute() + */ + public static Finishings[] + getAssociatedAttributeArray(Set set) + { + Finishings[] result = new Finishings[set.size()]; + int j = 0; + for (Attribute tmp : set) + { + result[j] = ((FinishingsSupported) tmp).getAssociatedAttribute(); + j++; + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/GeneratedNaturalLanguageSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/GeneratedNaturalLanguageSupported.java new file mode 100644 index 000000000..df1d33007 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/GeneratedNaturalLanguageSupported.java @@ -0,0 +1,89 @@ +/* GeneratedNaturalLanguageSupported.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.supported; + +import gnu.javax.print.ipp.attribute.NaturalLanguageSyntax; + +import javax.print.attribute.Attribute; +import javax.print.attribute.SupportedValuesAttribute; + +/** + * GeneratedNaturalLanguageSupported attribute as described + * in RFC 2911 section 4.4.20 provides the natural languages + * which are supported by the IPP implementation to be used + * in the name and text syntax attribute types. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class GeneratedNaturalLanguageSupported + extends NaturalLanguageSyntax + implements SupportedValuesAttribute +{ + + /** + * Creates a GeneratedNaturalLanguageSupported object. + * + * @param value the charset string value. + */ + public GeneratedNaturalLanguageSupported(String value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class GeneratedNaturalLanguageSupported itself. + */ + public Class getCategory() + { + return GeneratedNaturalLanguageSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "generated-natural-language-supported". + */ + public String getName() + { + return "generated-natural-language-supported"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/IppVersionsSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/IppVersionsSupported.java new file mode 100644 index 000000000..072d7499a --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/IppVersionsSupported.java @@ -0,0 +1,122 @@ +/* IppVersionsSupported.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.supported; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; +import javax.print.attribute.SupportedValuesAttribute; + +/** + * IppVersionsSupported attribute as described in RFC 2911 section + * 4.4.14 provides the value(s) (implemented as EnumSyntax) + * of the supported IPP versions. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class IppVersionsSupported extends EnumSyntax + implements SupportedValuesAttribute +{ + + // a keyword based attribute in IPP - int values just starting at 0 + + /** IPP version 1.0 */ + public static final IppVersionsSupported V_1_0 = + new IppVersionsSupported(0); + + /** IPP version 1.1 */ + public static final IppVersionsSupported V_1_1 = + new IppVersionsSupported(1); + + private static final String[] stringTable = { "1.0", "1.1" }; + + private static final IppVersionsSupported[] enumValueTable = { V_1_0, + V_1_1 }; + + /** + * Constructs a IppVersionsSupported object. + * + * @param value the enum value + */ + public IppVersionsSupported(int value) + { + super(value); + } + + /** + * Returns the category of this class. + * + * @return The class IppVersionsSupported itself. + */ + public Class getCategory() + { + return IppVersionsSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "ipp-versions-supported". + */ + public String getName() + { + return "ipp-versions-supported"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/JobHoldUntilSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/JobHoldUntilSupported.java new file mode 100644 index 000000000..2add4a0cd --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/JobHoldUntilSupported.java @@ -0,0 +1,134 @@ +/* JobHoldUntilSupported.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.supported; + +import java.util.Locale; + +import javax.print.attribute.Attribute; +import javax.print.attribute.SupportedValuesAttribute; +import javax.print.attribute.TextSyntax; + +/** + * JobHoldUntilSupported attribute provides the supported + * values for the attribute type job-hold-until. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class JobHoldUntilSupported extends TextSyntax + implements SupportedValuesAttribute +{ + + // a keyword/name based attribute in IPP + // can be extended by administrators + // standard values are predefined + + /** Job should be printed immediately. */ + public static final JobHoldUntilSupported NO_HOLD = + new JobHoldUntilSupported("no-hold", null); + + /** Job should be hold indefinitely. */ + public static final JobHoldUntilSupported INDEFINITE = + new JobHoldUntilSupported("indefinite", null); + + /** Job should be processed during the day. */ + public static final JobHoldUntilSupported DAY_TIME = + new JobHoldUntilSupported("day-time", null); + + /** Job should be processed in the evening. */ + public static final JobHoldUntilSupported EVENING = + new JobHoldUntilSupported("evening", null); + + /** Job should be processed during night. */ + public static final JobHoldUntilSupported NIGHT = + new JobHoldUntilSupported("night", null); + + /** Job should be processed during the weekend. */ + public static final JobHoldUntilSupported WEEKEND = + new JobHoldUntilSupported("weekend", null); + + /** + * Job should be processed as second-shift + * (after close of business). + */ + public static final JobHoldUntilSupported SECOND_SHIFT = + new JobHoldUntilSupported("second-shift", null); + + /** + * Job should be processed as third-shift + * (after midnight). + */ + public static final JobHoldUntilSupported THIRD_SHIFT = + new JobHoldUntilSupported("third-shift", null); + + /** + * Creates a JobHoldUntilSupported object with the + * given value and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @throws NullPointerException if value is null + */ + public JobHoldUntilSupported(String value, Locale locale) + { + super(value, locale); + } + + /** + * Returns category of this class. + * + * @return The class JobHoldUntilSupported itself. + */ + public Class getCategory() + { + return JobHoldUntilSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "job-hold-until-supported". + */ + public String getName() + { + return "job-hold-until-supported"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/JobSheetsSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/JobSheetsSupported.java new file mode 100644 index 000000000..aeb86ff10 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/JobSheetsSupported.java @@ -0,0 +1,148 @@ +/* JobSheetsSupported.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.supported; + +import gnu.javax.print.ipp.attribute.defaults.JobSheetsDefault; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Locale; +import java.util.Set; + +import javax.print.attribute.Attribute; +import javax.print.attribute.SupportedValuesAttribute; +import javax.print.attribute.TextSyntax; +import javax.print.attribute.standard.JobSheets; + +/** + * JobSheetsSupported attribute provides the supported values + * of the job-sheets attribute. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class JobSheetsSupported extends TextSyntax + implements SupportedValuesAttribute +{ + //a keyword/name based attribute in IPP + // can be extended by administrators + // standard values are predefined + + /** No job sheet is the default */ + public static final JobSheetsDefault NONE = + new JobSheetsDefault("none", Locale.getDefault()); + + /** A job sheet is the default */ + public static final JobSheetsDefault STANDARD = + new JobSheetsDefault("standard", Locale.getDefault()); + + /** + * Creates a JobSheetsSupported object with the + * given value and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @throws NullPointerException if value is null + */ + public JobSheetsSupported(String value, Locale locale) + { + super(value, locale); + } + + /** + * Returns category of this class. + * + * @return The class JobSheetsSupported itself. + */ + public Class getCategory() + { + return JobSheetsSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "job-sheets-supported". + */ + public String getName() + { + return "job-sheets-supported"; + } + + /** + * Returns the equally enum of the standard attribute class + * of this SupportedValuesAttribute enum. + *

    May return null if no value exists in JPS API.

    + * + * @return The enum of the standard attribute class. + */ + public JobSheets getAssociatedAttribute() + { + if (this.equals(JobSheetsDefault.NONE)) + return JobSheets.NONE; + if (this.equals(JobSheetsDefault.STANDARD)) + return JobSheets.STANDARD; + + return null; + } + + /** + * Constructs an array from a set of -supported attributes. + * @param set set to process + * @return The constructed array. + * + * @see #getAssociatedAttribute() + */ + public static JobSheets[] + getAssociatedAttributeArray(Set set) + { + ArrayList result = new ArrayList(); + int j = 0; + for (Attribute tmp : set) + { + JobSheets att = ((JobSheetsSupported) tmp).getAssociatedAttribute(); + if (att != null) + result.add(att); + j++; + } + return result.toArray(new JobSheets[result.size()]); + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/MediaSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/MediaSupported.java new file mode 100644 index 000000000..2684ebbec --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/MediaSupported.java @@ -0,0 +1,116 @@ +/* MediaSupported.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.supported; + +import gnu.javax.print.ipp.IppUtilities; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Locale; +import java.util.Set; + +import javax.print.attribute.Attribute; +import javax.print.attribute.SupportedValuesAttribute; +import javax.print.attribute.TextSyntax; +import javax.print.attribute.standard.Media; + +/** + * MediaSupported attribute provides the keyword values + * of the media types supported by the printer object. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class MediaSupported extends TextSyntax + implements SupportedValuesAttribute +{ + + /** + * Creates a MediaSupported object with the + * given value and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @throws NullPointerException if value is null + */ + public MediaSupported(String value, Locale locale) + { + super(value, locale); + } + + /** + * Returns category of this class. + * + * @return The class MediaSupported itself. + */ + public Class getCategory() + { + return MediaSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "media-supported". + */ + public String getName() + { + return "media-supported"; + } + + /** + * Constructs an array from a set of -supported attributes. + * @param set set to process + * @return The constructed array. + */ + public static Media[] getAssociatedAttributeArray(Set set) + { + Media tmp2; + ArrayList result = new ArrayList(); + for (Attribute tmp : set) + { + tmp2 = (Media) IppUtilities.getEnumAttribute("media", tmp.toString()); + if (tmp2 != null) + result.add(tmp2); + } + return result.toArray(new Media[result.size()]); + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/MultipleDocumentHandlingSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/MultipleDocumentHandlingSupported.java new file mode 100644 index 000000000..73e5921f1 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/MultipleDocumentHandlingSupported.java @@ -0,0 +1,176 @@ +/* MultipleDocumentHandlingSupported.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.print.ipp.attribute.supported; + +import gnu.javax.print.ipp.IppUtilities; + +import java.util.Iterator; +import java.util.Set; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; +import javax.print.attribute.SupportedValuesAttribute; +import javax.print.attribute.standard.MultipleDocumentHandling; + + +/** + * MultipleDocumentHandlingSupported provides the + * supported values for the MultipleDocumentHandling attribute. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class MultipleDocumentHandlingSupported extends EnumSyntax + implements SupportedValuesAttribute +{ + + //a keyword based attribute in IPP - int values just starting at 0 + + /** + * Supports only multiple documents treated as a single document. This + * applies to attributes which specify treatment of multiple document jobs. + */ + public static final MultipleDocumentHandlingSupported SINGLE_DOCUMENT = + new MultipleDocumentHandlingSupported(0); + + /** Supports multiple documents as uncollated copies */ + public static final MultipleDocumentHandlingSupported SEPARATE_DOCUMENTS_UNCOLLATED_COPIES = + new MultipleDocumentHandlingSupported(1); + + /** Supports multiple documents as collated copies */ + public static final MultipleDocumentHandlingSupported SEPARATE_DOCUMENTS_COLLATED_COPIES = + new MultipleDocumentHandlingSupported(2); + + /** + * Supports multiple documents where every single document starts + * with a new sheet. + */ + public static final MultipleDocumentHandlingSupported SINGLE_DOCUMENT_NEW_SHEET = + new MultipleDocumentHandlingSupported(3); + + private static final String[] stringTable = { "single-document", + "separate-documents-uncollated-copies", + "separate-documents-collated-copies", + "single-document-new-sheet" }; + + private static final MultipleDocumentHandlingSupported[] enumValueTable = + { SINGLE_DOCUMENT, SEPARATE_DOCUMENTS_UNCOLLATED_COPIES, + SEPARATE_DOCUMENTS_COLLATED_COPIES, SINGLE_DOCUMENT_NEW_SHEET}; + + /** + * Constructs a MultipleDocumentHandlingSupported object. + * + * @param value the enum value + */ + protected MultipleDocumentHandlingSupported(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class MultipleDocumentHandlingSupported itself. + */ + public Class getCategory() + { + return MultipleDocumentHandlingSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "multiple-document-handling-supported". + */ + public String getName() + { + return "multiple-document-handling-supported"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } + + /** + * Returns the equally enum of the standard attribute class + * of this SupportedValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public MultipleDocumentHandling getAssociatedAttribute() + { + return (MultipleDocumentHandling) IppUtilities.getEnumAttribute( + "multiple-document-handling", new Integer(getValue())); + } + + /** + * Constructs an array from a set of -supported attributes. + * @param set set to process + * @return The constructed array. + * + * @see #getAssociatedAttribute() + */ + public static MultipleDocumentHandling[] + getAssociatedAttributeArray(Set set) + { + MultipleDocumentHandling[] result = new MultipleDocumentHandling[set.size()]; + int j = 0; + for (Attribute tmp : set) + { + result[j] = ((MultipleDocumentHandlingSupported) tmp).getAssociatedAttribute(); + j++; + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/MultipleDocumentJobsSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/MultipleDocumentJobsSupported.java new file mode 100644 index 000000000..1b2998456 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/MultipleDocumentJobsSupported.java @@ -0,0 +1,119 @@ +/* MultipleDocumentJobsSupported.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.supported; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; +import javax.print.attribute.SupportedValuesAttribute; + +/** + * MultipleDocumentJobsSupported specifies if a printer + * supported multiple documents in one job. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public class MultipleDocumentJobsSupported extends EnumSyntax + implements SupportedValuesAttribute +{ + + /** Multiple documents per job are not supported. */ + public static final MultipleDocumentJobsSupported NOT_SUPPORTED = + new MultipleDocumentJobsSupported(0); + + /** Multiple documents per job are supported. */ + public static final MultipleDocumentJobsSupported SUPPORTED = + new MultipleDocumentJobsSupported(1); + + private static final String[] stringTable = { "not-supported", "supported" }; + + private static final MultipleDocumentJobsSupported[] enumValueTable = + { NOT_SUPPORTED, SUPPORTED }; + + /** + * Constructs a MultipleDocumentJobsSupported object. + * + * @param value the enum value + */ + protected MultipleDocumentJobsSupported(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class MultipleDocumentJobsSupported itself. + */ + public Class getCategory() + { + return MultipleDocumentJobsSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "multiple-document-jobs-supported". + */ + public String getName() + { + return "multiple-document-jobs-supported"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/OperationsSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/OperationsSupported.java new file mode 100644 index 000000000..a059c89a5 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/OperationsSupported.java @@ -0,0 +1,231 @@ +/* OperationsSupported.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.supported; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; +import javax.print.attribute.SupportedValuesAttribute; + +/** + * OperationsSupported specifies the enums of the operations + * supported by a given printer or job object. The attribute is further + * specified in RFC 2911 section 4.4.15. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class OperationsSupported extends EnumSyntax + implements SupportedValuesAttribute +{ + /* + * Value Operation Name + ----------------- ------------------------------------- + 0x0000 reserved, not used + 0x0001 reserved, not used + 0x0002 Print-Job + 0x0003 Print-URI + 0x0004 Validate-Job + 0x0005 Create-Job + 0x0006 Send-Document + 0x0007 Send-URI + 0x0008 Cancel-Job + 0x0009 Get-Job-Attributes + 0x000A Get-Jobs + 0x000B Get-Printer-Attributes + 0x000C Hold-Job + 0x000D Release-Job + 0x000E Restart-Job + 0x000F reserved for a future operation + 0x0010 Pause-Printer + 0x0011 Resume-Printer + 0x0012 Purge-Jobs + 0x0013-0x3FFF reserved for future IETF standards track operations + 0x4000-0x8FFF reserved for vendor extensions + */ + + // standard ipp 1.1 operations + + /** + * Operation to print a job in one request/response. */ + public static final OperationsSupported PRINT_JOB = + new OperationsSupported(0x02); + + /** Operation to print a document from an URI */ + public static final OperationsSupported PRINT_URI = + new OperationsSupported(0x03); + + /** Operation to validate a job before submission. */ + public static final OperationsSupported VALIDATE_JOB = + new OperationsSupported(0x04); + + /** + * Operation to create an initial job for use with multiple document per job. + */ + public static final OperationsSupported CREATE_JOB = + new OperationsSupported(0x05); + + /** + * Operation to send a document to a multidoc job created via CREATE_JOB + */ + public static final OperationsSupported SEND_DOCUMENT = + new OperationsSupported(0x06); + + /** + * Operation to send a document uri to a multidoc job created + * via CREATE_JOB. The document accessible from this URI will be printed. + */ + public static final OperationsSupported SEND_URI = + new OperationsSupported(0x07); + + /** Operation to cancel a job by its ID or name. */ + public static final OperationsSupported CANCEL_JOB = + new OperationsSupported(0x08); + + /** Operation to get job attributes of a current job. */ + public static final OperationsSupported GET_JOB_ATTRIBUTES = + new OperationsSupported(0x09); + + /** Operation to pause a printer. */ + public static final OperationsSupported PAUSE_PRINTER = + new OperationsSupported(0x10); + + /** Operation to get all currently queued or processed jobs. */ + public static final OperationsSupported GET_JOBS = + new OperationsSupported(0x0A); + + /** Operation to get the attributes of a printer. */ + public static final OperationsSupported GET_PRINTER_ATTRIBUTES = + new OperationsSupported(0x0B); + + /** Operation to put a job on hold by its ID or name. */ + public static final OperationsSupported HOLD_JOB = + new OperationsSupported(0x0C); + + /** Operation to release a job by its ID or name. */ + public static final OperationsSupported RELEASE_JOB = + new OperationsSupported(0x0D); + + /** Operation to restart a job by its ID or name. */ + public static final OperationsSupported RESTART_JOB = + new OperationsSupported(0x0E); + + /** Not yet an operation - reserved for futher use. */ + public static final OperationsSupported RESERVED = + new OperationsSupported(0x0F); + + /** Operation to resume a printer. */ + public static final OperationsSupported RESUME_PRINTER = + new OperationsSupported(0x11); + + /** Operation to remove all jobs from a printer regardless of state. */ + public static final OperationsSupported PURGE_JOBS = + new OperationsSupported(0x12); + + + private static final String[] stringTable = { "print-job", "print-uri", + "validate-job", "create-job", + "send-document", "send-uri", + "cancel-job", "get-job-attributes", + "pause-printer", "get-jobs", + "get-printer-attributes", "hold-job", + "release-job", "restart-job", "reserved", + "resume-printer", "purge-job"}; + + private static final OperationsSupported[] enumValueTable = + { PRINT_JOB, PRINT_URI, VALIDATE_JOB, CREATE_JOB, SEND_DOCUMENT, SEND_URI, + CANCEL_JOB, GET_JOB_ATTRIBUTES, PAUSE_PRINTER, GET_JOBS, GET_PRINTER_ATTRIBUTES, + HOLD_JOB, RELEASE_JOB, RESTART_JOB, RESERVED, RESUME_PRINTER, PURGE_JOBS}; + + + /** + * Constructs a OperationsSupported object. + * + * @param value the enum value + */ + protected OperationsSupported(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class OperationsSupported itself. + */ + public Class getCategory() + { + return OperationsSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "operations-supported". + */ + public String getName() + { + return "operations-supported"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } + + // we start with 2 + protected int getOffset() + { + return 2; + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/OrientationRequestedSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/OrientationRequestedSupported.java new file mode 100644 index 000000000..4b87c53a5 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/OrientationRequestedSupported.java @@ -0,0 +1,178 @@ +/* OrientationRequestedSupported.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.print.ipp.attribute.supported; + +import gnu.javax.print.ipp.IppUtilities; + +import java.util.Iterator; +import java.util.Set; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; +import javax.print.attribute.SupportedValuesAttribute; +import javax.print.attribute.standard.OrientationRequested; + + +/** + * The OrientationRequestedSupported attribute provides + * the supported values for the job attribute orientation-requested. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class OrientationRequestedSupported extends EnumSyntax + implements SupportedValuesAttribute +{ + + /** Orientation as portrait. */ + public static final OrientationRequestedSupported PORTRAIT = + new OrientationRequestedSupported(3); + + /** Orientation as landscape. */ + public static final OrientationRequestedSupported LANDSCAPE = + new OrientationRequestedSupported(4); + + /** Orientation as reversed landscape. */ + public static final OrientationRequestedSupported REVERSE_LANDSCAPE = + new OrientationRequestedSupported(5); + + /** Orientation as reversed portrait. */ + public static final OrientationRequestedSupported REVERSE_PORTRAIT = + new OrientationRequestedSupported(6); + + + private static final String[] stringTable = { "portrait", "landscape", + "reverse-landscape", + "reverse-portrait" }; + + private static final OrientationRequestedSupported[] + enumValueTable = { PORTRAIT, LANDSCAPE, + REVERSE_LANDSCAPE, REVERSE_PORTRAIT }; + + /** + * Constructs a OrientationRequestedSupported object. + * + * @param value the value + */ + protected OrientationRequestedSupported(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class OrientationRequestedSupported itself. + */ + public Class getCategory() + { + return OrientationRequestedSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "orientation-requested-supported". + */ + public String getName() + { + return "orientation-requested-supported"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } + + /** + * Returns the lowest used value by the enumerations of this class. + * . + * @return The lowest value used. + */ + protected int getOffset() + { + return 3; + } + + /** + * Returns the equally enum of the standard attribute class + * of this SupportedValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public OrientationRequested getAssociatedAttribute() + { + return (OrientationRequested) IppUtilities.getEnumAttribute( + "orientation-requested", new Integer(getValue())); + } + + /** + * Constructs an array from a set of -supported attributes. + * @param set set to process + * @return The constructed array. + * + * @see #getAssociatedAttribute() + */ + public static OrientationRequested[] + getAssociatedAttributeArray(Set set) + { + OrientationRequested[] result = new OrientationRequested[set.size()]; + int j = 0; + for (Attribute tmp : set) + { + result[j] = ((OrientationRequestedSupported) tmp).getAssociatedAttribute(); + j++; + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/PageRangesSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/PageRangesSupported.java new file mode 100644 index 000000000..c58f76748 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/PageRangesSupported.java @@ -0,0 +1,117 @@ +/* PageRangesSupported.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.print.ipp.attribute.supported; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; +import javax.print.attribute.SupportedValuesAttribute; + +/** + * PageRangesSupported is a boolean typed + * attribute indicating (as EnumSyntax) if page ranges + * are supported. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class PageRangesSupported extends EnumSyntax + implements SupportedValuesAttribute +{ + /** Page ranges are not supported. */ + public static final PageRangesSupported NOT_SUPPORTED = + new PageRangesSupported(0); + + /** Page ranges are supported. */ + public static final PageRangesSupported SUPPORTED = + new PageRangesSupported(1); + + private static final String[] stringTable = { "not-supported", "supported" }; + + private static final PageRangesSupported[] enumValueTable = { NOT_SUPPORTED, + SUPPORTED }; + + /** + * Constructs a PageRangesSupported object. + * + * @param value the enum value + */ + protected PageRangesSupported(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class PageRangesSupported itself. + */ + public Class getCategory() + { + return PageRangesSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "page-ranges-supported". + */ + public String getName() + { + return "page-ranges-supported"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/PrintQualitySupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/PrintQualitySupported.java new file mode 100644 index 000000000..25cbf9f0b --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/PrintQualitySupported.java @@ -0,0 +1,169 @@ +/* PrintQualitySupported.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.print.ipp.attribute.supported; + +import gnu.javax.print.ipp.IppUtilities; + +import java.util.Iterator; +import java.util.Set; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; +import javax.print.attribute.SupportedValuesAttribute; +import javax.print.attribute.standard.PrintQuality; + + +/** + * PrintQualitySupported provides the + * supported values for the print-quality attribute. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class PrintQualitySupported extends EnumSyntax + implements SupportedValuesAttribute +{ + /** Draft quality of the printer. */ + public static final PrintQualitySupported DRAFT = + new PrintQualitySupported(3); + + /** Normal quality of the printer. */ + public static final PrintQualitySupported NORMAL = + new PrintQualitySupported(4); + + /** High quality of the printer. */ + public static final PrintQualitySupported HIGH = + new PrintQualitySupported(5); + + private static final String[] stringTable = { "draft", "normal", "high" }; + + private static final PrintQualitySupported[] enumValueTable = { DRAFT, + NORMAL, + HIGH }; + + /** + * Constructs a PrintQualitySupported object. + * + * @param value the value of the enum + */ + protected PrintQualitySupported(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class PrintQualitySupported itself. + */ + public Class getCategory() + { + return PrintQualitySupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "print-quality-supported". + */ + public String getName() + { + return "print-quality-supported"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } + + /** + * Returns the lowest used value by the enumerations of this class. + * . + * @return The lowest value used. + */ + protected int getOffset() + { + return 3; + } + + /** + * Returns the equally enum of the standard attribute class + * of this SupportedValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public PrintQuality getAssociatedAttribute() + { + return (PrintQuality) IppUtilities.getEnumAttribute( + "print-quality", new Integer(getValue())); + } + + /** + * Constructs an array from a set of -supported attributes. + * @param set set to process + * @return The constructed array. + * + * @see #getAssociatedAttribute() + */ + public static PrintQuality[] getAssociatedAttributeArray(Set set) + { + PrintQuality[] result = new PrintQuality[set.size()]; + int j = 0; + for (Attribute tmp : set) + { + result[j] = ((PrintQualitySupported) tmp).getAssociatedAttribute(); + j++; + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/PrinterResolutionSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/PrinterResolutionSupported.java new file mode 100644 index 000000000..eb50aaac5 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/PrinterResolutionSupported.java @@ -0,0 +1,142 @@ +/* PrinterResolutionSupported.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.print.ipp.attribute.supported; + +import java.util.Iterator; +import java.util.Set; + +import javax.print.attribute.Attribute; +import javax.print.attribute.ResolutionSyntax; +import javax.print.attribute.SupportedValuesAttribute; +import javax.print.attribute.standard.PrinterResolution; + + +/** + * The PrinterResolutionSupported attribute provides + * the supported values for the job attribute printer-resolution. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class PrinterResolutionSupported extends ResolutionSyntax + implements SupportedValuesAttribute +{ + + /** + * Creates a PrinterResolutionSupported object with the + * given arguments. + * + * @param crossFeedResolution the cross feed resolution + * @param feedResolution the feed resolution + * @param units the unit to use (e.g. {@link #DPCM} or {@link #DPI}) + * + * @exception IllegalArgumentException if preconditions fail + */ + public PrinterResolutionSupported(int crossFeedResolution, + int feedResolution, int units) + { + super(crossFeedResolution, feedResolution, units); + } + + /** + * Tests if the given object is equal to this object. + * + * @param obj the object to test + * + * @return true if both objects are equal, + * false otherwise. + */ + public boolean equals(Object obj) + { + if(! (obj instanceof PrinterResolutionSupported)) + return false; + + return super.equals(obj); + } + + /** + * Returns category of this class. + * + * @return The class PrinterResolutionSupported itself. + */ + public Class getCategory() + { + return PrinterResolutionSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "printer-resolution-supported". + */ + public String getName() + { + return "printer-resolution-supported"; + } + + /** + * Returns the equally enum of the standard attribute class + * of this SupportedValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public PrinterResolution getAssociatedAttribute() + { + return new PrinterResolution(getCrossFeedResolutionDphi(), + getFeedResolutionDphi(), 1); + } + + /** + * Constructs an array from a set of -supported attributes. + * @param set set to process + * @return The constructed array. + * + * @see #getAssociatedAttribute() + */ + public static PrinterResolution[] + getAssociatedAttributeArray(Set set) + { + PrinterResolution[] result = new PrinterResolution[set.size()]; + int j = 0; + for (Attribute tmp : set) + { + result[j] = ((PrinterResolutionSupported) tmp).getAssociatedAttribute(); + j++; + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/PrinterUriSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/PrinterUriSupported.java new file mode 100644 index 000000000..0eed39c6c --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/PrinterUriSupported.java @@ -0,0 +1,89 @@ +/* PrinterUriSupported.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.supported; + +import java.net.URI; + +import javax.print.attribute.Attribute; +import javax.print.attribute.SupportedValuesAttribute; +import javax.print.attribute.URISyntax; + +/** + * PrinterUriSupported attribute as described in RFC 2911 section + * 4.4.1 contains one of the URIs the printer supported for + * job processing (e.g. one with authentication). + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class PrinterUriSupported extends URISyntax + implements SupportedValuesAttribute +{ + + /** + * Creates a PrinterUriSupported object. + * + * @param uri the URI value for the syntax + * @throws NullPointerException if uri is null + */ + public PrinterUriSupported(URI uri) + { + super(uri); + } + + /** + * Returns category of this class. + * + * @return The class PrinterUriSupported itself. + */ + public Class getCategory() + { + return PrinterUriSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "printer-uri-supported". + */ + public String getName() + { + return "printer-uri-supported"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/SidesSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/SidesSupported.java new file mode 100644 index 000000000..eff82c143 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/SidesSupported.java @@ -0,0 +1,137 @@ +/* SidesSupported.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.print.ipp.attribute.supported; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; +import javax.print.attribute.SupportedValuesAttribute; + + +/** + * SidesSupported provides the + * supported values for the sides attribute. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class SidesSupported extends EnumSyntax + implements SupportedValuesAttribute +{ + + /** Specifies that each page should be printed on one sheet. */ + public static final SidesSupported ONE_SIDED = new SidesSupported(0); + + /** + * Specifies that two following pages should be printed on the + * front and back of one sheet for binding on the long edge. + */ + public static final SidesSupported TWO_SIDED_LONG_EDGE = + new SidesSupported(1); + + /** + * Specifies that two following pages should be printed on the + * front and back of one sheet for binding on the short edge. + */ + public static final SidesSupported TWO_SIDED_SHORT_EDGE = + new SidesSupported(2); + + /** An alias constant for "two sided long edge". */ + public static final SidesSupported DUPLEX = new SidesSupported(1); + + /** An alias constant for "two sided short edge". */ + public static final SidesSupported TUMBLE = new SidesSupported(2); + + private static final String[] stringTable = { "one-sided", + "two-sided-long-edge", + "two-sided-short-edge" }; + + private static final SidesSupported[] + enumValueTable = { ONE_SIDED, TWO_SIDED_LONG_EDGE, + TWO_SIDED_SHORT_EDGE }; + + + /** + * Creates a SidesSupported object. + * + * @param value the value of the enum + */ + protected SidesSupported(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class SidesSupported itself. + */ + public Class getCategory() + { + return SidesSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "sides-supported". + */ + public String getName() + { + return "sides-supported"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/UriAuthenticationSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/UriAuthenticationSupported.java new file mode 100644 index 000000000..dc1a29f5c --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/UriAuthenticationSupported.java @@ -0,0 +1,142 @@ +/* UriAuthenticationSupported.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.supported; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; +import javax.print.attribute.SupportedValuesAttribute; + +/** + * UriAuthenticationSupported attribute as described in RFC 2911 section + * 4.4.2 provides the keywords (implemented as EnumSyntax) which + * authentication methods are supported by the printer object. This + * includes a value of none. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class UriAuthenticationSupported extends EnumSyntax + implements SupportedValuesAttribute +{ + + // a keyword based attribute in IPP - int values just starting at 0 + + /** Supports no authentication - assumes anonymous process */ + public static final UriAuthenticationSupported NONE = + new UriAuthenticationSupported(0); + + /** + * The authenticated user assumed is the value of the + * "requesting-user-name" operation attribute supplied + * with the operation. + */ + public static final UriAuthenticationSupported REQUESTING_USER_NAME = + new UriAuthenticationSupported(1); + + /** Supports HTTP basic authentication (RFC 2617) */ + public static final UriAuthenticationSupported BASIC = + new UriAuthenticationSupported(2); + + /** Supports HTTP digest authentication (RFC 2617) */ + public static final UriAuthenticationSupported DIGEST = + new UriAuthenticationSupported(3); + + /** Supports authentication through a client provided certificate */ + public static final UriAuthenticationSupported CERTIFICATE = + new UriAuthenticationSupported(4); + + private static final String[] stringTable = { "none", + "requesting-user-name", + "basic", "digest", + "certificate" }; + + private static final UriAuthenticationSupported[] enumValueTable = + { NONE, REQUESTING_USER_NAME, BASIC, DIGEST, CERTIFICATE }; + + /** + * Constructs a UriAuthenticationSupported object. + * + * @param value the enum value + */ + public UriAuthenticationSupported(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class UriAuthenticationSupported itself. + */ + public Class getCategory() + { + return UriAuthenticationSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "uri-authentication-supported". + */ + public String getName() + { + return "uri-authentication-supported"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/UriSecuritySupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/UriSecuritySupported.java new file mode 100644 index 000000000..03396978f --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/UriSecuritySupported.java @@ -0,0 +1,127 @@ +/* UriSecuritySupported.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.print.ipp.attribute.supported; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; +import javax.print.attribute.SupportedValuesAttribute; + +/** + * UriSecuritySupported attribute as described in RFC 2911 section + * 4.4.3 provides the keywords (implemented as EnumSyntax) for + * the security mechanisms supported by the corresponding uri's + * supported (same place in setOf). + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class UriSecuritySupported extends EnumSyntax + implements SupportedValuesAttribute +{ + + // a keyword based attribute in IPP - int values just starting at 0 + + /** The URI has no secure communication */ + public static final UriSecuritySupported NONE = + new UriSecuritySupported(0); + + /** The URI has SSL3 communication */ + public static final UriSecuritySupported SSL3 = + new UriSecuritySupported(1); + + /** The URI has TLS (RFC 2246) communication */ + public static final UriSecuritySupported TLS = + new UriSecuritySupported(2); + + private static final String[] stringTable = { "none", "ssl3", "tls" }; + + private static final UriSecuritySupported[] enumValueTable = { NONE, + SSL3, TLS }; + + /** + * Constructs a UriSecuritySupported object. + * + * @param value the enum value + */ + public UriSecuritySupported(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class UriSecuritySupported itself. + */ + public Class getCategory() + { + return UriSecuritySupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "uri-security-supported". + */ + public String getName() + { + return "uri-security-supported"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } + +} diff --git a/libjava/classpath/gnu/javax/rmi/CORBA/CorbaInput.java b/libjava/classpath/gnu/javax/rmi/CORBA/CorbaInput.java new file mode 100644 index 000000000..5880c85c5 --- /dev/null +++ b/libjava/classpath/gnu/javax/rmi/CORBA/CorbaInput.java @@ -0,0 +1,297 @@ +/* CorbaInput.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.rmi.CORBA; + +import gnu.CORBA.CDR.gnuRuntime; + +import org.omg.CORBA_2_3.portable.InputStream; + +import java.io.DataInputStream; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectInputStream; +import java.io.Serializable; + +/** + * Converts calls on java ObjectOutputStream to calls on CORBA OutputStream. A + * class to substitute for objects using readObject method. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class CorbaInput + extends ObjectInputStream + implements ObjectInput +{ + + /** + * The underlying CORBA stream from where the actual input is taken. + */ + public InputStream stream; + + /** + * The utility class to write the object fields in default way. + */ + final RmiUtilities util; + + /** + * The object currently being read. + */ + Object current; + + /** + * The offset of the object currently being read. + */ + int offset; + + /** + * The repository id of the object currently being read. + */ + String rid; + + /** + * The runtime, related to the object currently being read. + */ + gnuRuntime runtime; + + /** + * Create an instance, delegating calls to the given CORBA stream. + */ + public CorbaInput(InputStream an_input, Object firstObject, + RmiUtilities an_util, int an_offset, String a_rid, + gnuRuntime a_runtime) + throws Exception + { + stream = an_input; + current = firstObject; + util = an_util; + + offset = an_offset; + rid = a_rid; + runtime = a_runtime; + } + + /** @inheritDoc */ + public int available() + throws IOException + { + return stream.available(); + } + + /** + * No action. + */ + public void close() + throws IOException + { + } + + /** @inheritDoc */ + public void defaultReadObject() + throws IOException, ClassNotFoundException + { + util.readFields(offset, rid, (Serializable) current, stream, runtime); + } + + /** @inheritDoc */ + public void mark(int readlimit) + { + stream.mark(readlimit); + } + + /** @inheritDoc */ + public boolean markSupported() + { + return stream.markSupported(); + } + + /** @inheritDoc */ + public int read() + throws IOException + { + return stream.read(); + } + + /** @inheritDoc */ + public int read(byte[] buf, int off, int len) + throws IOException + { + return stream.read(buf, off, len); + } + + /** @inheritDoc */ + public int read(byte[] b) + throws IOException + { + return stream.read(b); + } + + /** @inheritDoc */ + public boolean readBoolean() + throws IOException + { + return stream.read_boolean(); + } + + /** @inheritDoc */ + public byte readByte() + throws IOException + { + return (byte) stream.read(); + } + + /** @inheritDoc */ + public char readChar() + throws IOException + { + return stream.read_char(); + } + + /** @inheritDoc */ + public double readDouble() + throws IOException + { + return stream.read_double(); + } + + /** @inheritDoc */ + public float readFloat() + throws IOException + { + return stream.read_float(); + } + + /** @inheritDoc */ + public void readFully(byte[] buf, int off, int len) + throws IOException + { + // This class only reads from the buffered streams. + stream.read(buf, off, len); + } + + /** @inheritDoc */ + public void readFully(byte[] buf) + throws IOException + { + // This class only reads from the buffered streams. + stream.read(buf); + } + + /** @inheritDoc */ + public int readInt() + throws IOException + { + return stream.read_long(); + } + + /** @inheritDoc */ + public String readLine() + throws IOException + { + return new DataInputStream(this).readLine(); + } + + /** @inheritDoc */ + public long readLong() + throws IOException + { + return stream.read_longlong(); + } + + /** @inheritDoc */ + public short read_short() + throws IOException + { + return stream.read_short(); + } + + /** @inheritDoc */ + public int readUnsignedByte() + throws IOException + { + return (stream.read() & 0xFF); + } + + /** @inheritDoc */ + public int readUnsignedShort() + throws IOException + { + return (stream.read_short() & 0xFFFF); + } + + /** + * Read as wide string (not as UTF). + */ + public String readUTF() + throws IOException + { + return stream.read_wstring(); + } + + /** @inheritDoc */ + public void reset() + throws IOException + { + stream.reset(); + } + + /** @inheritDoc */ + public long skip(long n) + throws IOException + { + return stream.skip(n); + } + + /** @inheritDoc */ + public int skipBytes(int len) + throws IOException + { + return (int) stream.skip(len); + } + + /** + * Objects are read as abstract interfaces. + */ + protected Object readObjectOverride() + throws IOException, ClassNotFoundException + { + current = stream.read_abstract_interface(); + return current; + } + +} diff --git a/libjava/classpath/gnu/javax/rmi/CORBA/CorbaOutput.java b/libjava/classpath/gnu/javax/rmi/CORBA/CorbaOutput.java new file mode 100644 index 000000000..1d1480511 --- /dev/null +++ b/libjava/classpath/gnu/javax/rmi/CORBA/CorbaOutput.java @@ -0,0 +1,219 @@ +/* CorbaOutput.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.rmi.CORBA; + +import org.omg.CORBA_2_3.portable.OutputStream; + +import java.io.IOException; +import java.io.ObjectOutput; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +/** + * A class to substitute as an ObjectOutputStream for objects using writeObject + * method. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class CorbaOutput + extends ObjectOutputStream + implements ObjectOutput +{ + /** + * A CORBA stream where the output is forwarded. + */ + final OutputStream stream; + + /** + * The utility class to write the object fields in default way. + */ + final RmiUtilities util; + + /** + * The object currently being written. + */ + Object current; + + /** + * Create an instance, delegating calls to the given CORBA stream. + */ + public CorbaOutput(OutputStream an_output, Object firstObject, + RmiUtilities an_util) + throws Exception + { + stream = an_output; + current = firstObject; + util = an_util; + } + + /** + * No action. + */ + public void close() + throws IOException + { + } + + /** @inheritDoc */ + public void flush() + throws IOException + { + stream.flush(); + } + + /** @inheritDoc */ + public void write(byte[] buf, int off, int len) + throws IOException + { + stream.write(buf, off, len); + } + + /** @inheritDoc */ + public void write(byte[] buf) + throws IOException + { + stream.write(buf); + } + + /** @inheritDoc */ + public void write(int val) + throws IOException + { + stream.write(val); + } + + /** @inheritDoc */ + public void writeBoolean(boolean val) + throws IOException + { + stream.write_boolean(val); + } + + /** @inheritDoc */ + public void writeByte(int val) + throws IOException + { + stream.write(val); + } + + /** @inheritDoc */ + public void writeBytes(String str) + throws IOException + { + stream.write_string(str); + } + + /** @inheritDoc */ + public void writeChar(int val) + throws IOException + { + stream.write_wchar((char) val); + } + + /** @inheritDoc */ + public void writeChars(String str) + throws IOException + { + stream.write_char_array(str.toCharArray(), 0, str.length()); + } + + /** @inheritDoc */ + public void writeDouble(double val) + throws IOException + { + stream.write_double(val); + } + + /** @inheritDoc */ + public void writeFloat(float val) + throws IOException + { + stream.write_float(val); + } + + /** @inheritDoc */ + public void writeInt(int val) + throws IOException + { + stream.write_long(val); + } + + /** @inheritDoc */ + public void writeLong(long val) + throws IOException + { + stream.write_longlong(val); + } + + /** + * Objects are written as abstract interfaces. + */ + protected void writeObjectOverride(Object obj) + throws IOException + { + current = obj; + stream.write_abstract_interface(obj); + } + + /** @inheritDoc */ + public void writeShort(int val) + throws IOException + { + stream.write_short((short) val); + } + + /** + * Such strings are written as wide strings, not as UTF. + */ + public void writeUTF(String str) + throws IOException + { + stream.write_wstring(str); + } + + /** + * @inheritDoc + */ + public void defaultWriteObject() + throws IOException + { + util.writeFields(stream, (Serializable) current); + } + +} diff --git a/libjava/classpath/gnu/javax/rmi/CORBA/DefaultWriteObjectTester.java b/libjava/classpath/gnu/javax/rmi/CORBA/DefaultWriteObjectTester.java new file mode 100644 index 000000000..b925428b0 --- /dev/null +++ b/libjava/classpath/gnu/javax/rmi/CORBA/DefaultWriteObjectTester.java @@ -0,0 +1,85 @@ +/* DefaultWriteObjectTester.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.rmi.CORBA; + +import gnu.CORBA.CDR.BufferedCdrOutput; + +import java.io.IOException; + +/** + * Tests if the defaultWriteObject method has been called. + * This information is required by RMI-IIOP header. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class DefaultWriteObjectTester + extends CorbaOutput +{ + /** + * The flag, indicating, that the defaultWriteObject method was called. + */ + public boolean dwo_called; + + /** + * Create an instance, delegating calls to the given CORBA stream. + */ + public DefaultWriteObjectTester(Object firstObject) + throws Exception + { + super(new BufferedCdrOutput(), firstObject, null); + } + + /** + * Set the flag that defaultWriteObject was called. + */ + public void defaultWriteObject() + throws IOException + { + dwo_called = true; + } + + /** + * Do not write other objects. + */ + protected void writeObjectOverride(Object obj) + throws IOException + { + } + +} diff --git a/libjava/classpath/gnu/javax/rmi/CORBA/DelegateFactory.java b/libjava/classpath/gnu/javax/rmi/CORBA/DelegateFactory.java new file mode 100644 index 000000000..a12afd51e --- /dev/null +++ b/libjava/classpath/gnu/javax/rmi/CORBA/DelegateFactory.java @@ -0,0 +1,107 @@ +/* DelegateFactory.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.rmi.CORBA; + +import gnu.CORBA.ObjectCreator; + + +/** + * This class produces delegates, using the system properties. If not + * corresponding property is specified, returns default implementations. + * + * @author Wu Gansha (gansha.wu@intel.com) + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class DelegateFactory +{ + /** + * The name to get a stub delegate. + */ + public static final String STUB = "Stub"; + + /** + * The name to get the util delegate. + */ + public static final String UTIL = "Util"; + + /** + * The name to get the ValueHandler delegate. + */ + public static final String VALUEHANDLER = "ValueHandler"; + + /** + * The name to get the PortableRemoteObject delegate. + */ + public static final String PORTABLE_REMOTE_OBJECT = "PortableRemoteObject"; + + /** + * Get an instance of the given delegate. As in all cases the singleton + * instance is used, the caching here would be redundant. + * + * @param type a delegate type. + * + * @return the associated delegate. + * + * @throws InternalError if the delegate class, indicated in the system + * properties, cannot be instantiated. + */ + public static Object getInstance(String type) + throws InternalError + { + String propertyName = "javax.rmi.CORBA." + type + "Class"; + String dcname = System.getProperty(propertyName); + if (dcname == null) + { + // // No javax.rmi.CORBA.XXXClass property sepcified. + dcname = "gnu.javax.rmi.CORBA." + type + "DelegateImpl"; + } + try + { + Class dclass = ObjectCreator.forName(dcname); + return dclass.newInstance(); + } + catch (Exception e) + { + InternalError ierr = new InternalError("Exception when trying to get " + + type + "delegate instance:" + dcname); + ierr.initCause(e); + throw ierr; + } + } +} diff --git a/libjava/classpath/gnu/javax/rmi/CORBA/GetDelegateInstanceException.java b/libjava/classpath/gnu/javax/rmi/CORBA/GetDelegateInstanceException.java new file mode 100644 index 000000000..f8aca0d47 --- /dev/null +++ b/libjava/classpath/gnu/javax/rmi/CORBA/GetDelegateInstanceException.java @@ -0,0 +1,55 @@ +/* GetDelegateInstanceException.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.rmi.CORBA; + +public class GetDelegateInstanceException + extends Exception +{ + private Throwable next; + + public GetDelegateInstanceException(String msg) + { + super(msg); + } + + public GetDelegateInstanceException(String msg, Throwable next) + { + super(msg, next); + } +} diff --git a/libjava/classpath/gnu/javax/rmi/CORBA/PortableRemoteObjectDelegateImpl.java b/libjava/classpath/gnu/javax/rmi/CORBA/PortableRemoteObjectDelegateImpl.java new file mode 100644 index 000000000..f430ac123 --- /dev/null +++ b/libjava/classpath/gnu/javax/rmi/CORBA/PortableRemoteObjectDelegateImpl.java @@ -0,0 +1,362 @@ +/* PortableRemoteObjectDelegateImpl.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.rmi.CORBA; + +import gnu.CORBA.SimpleDelegate; +import gnu.CORBA.Unexpected; +import gnu.CORBA.Poa.LocalDelegate; +import gnu.CORBA.Poa.ORB_1_4; +import gnu.CORBA.Poa.AOM; + +import java.rmi.NoSuchObjectException; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.server.RMIClassLoader; + +import javax.rmi.CORBA.PortableRemoteObjectDelegate; +import javax.rmi.CORBA.Stub; +import javax.rmi.CORBA.Tie; +import javax.rmi.CORBA.Util; + +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.ORB; +import org.omg.CORBA.portable.Delegate; +import org.omg.CORBA.portable.ObjectImpl; +import org.omg.PortableServer.POA; +import org.omg.PortableServer.POAHelper; +import org.omg.PortableServer.Servant; +import org.omg.PortableServer.POAManagerPackage.State; + +/** + * Implements PortableRemoteObjectDelegate. + * + * @author Wu Gansha (gansha.wu@intel.com) (stub) + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) (implementation) + */ +public class PortableRemoteObjectDelegateImpl + implements PortableRemoteObjectDelegate +{ + /** + *

    + * Makes the remote object a_target ready for remote + * communication using the same communications runtime as for the passed + * a_source parameter. The a_target is connected to the same + * ORB (and, if applicable, to the same POA) as the a_source. + * + * @param a_target the target to connect to ORB, must be an instance of either + * {@link ObjectImpl} (Stubs and old-style ties) or {@link Servant} (POA-bases + * ties). + * + * @param a_source the object, providing the connection information, must be + * an instance of either {@link ObjectImpl} (Stubs and old-style ties) or + * {@link Servant} (POA-bases ties). + * + * @throws RemoteException if the target is already connected to another ORB. + */ + public void connect(Remote a_target, Remote a_source) + throws RemoteException + { + ORB orb = null; + POA poa = null; + boolean ok = false; + + try + { + if (a_source instanceof Servant) + { + Servant s = (Servant) a_source; + orb = s._orb(); + poa = s._poa(); + ok = true; + } + + if (!ok && a_source instanceof ObjectImpl) + { + ObjectImpl o = (ObjectImpl) a_source; + orb = o._orb(); + ok = true; + try + { + if (orb instanceof ORB_1_4) + { + // POA information available. + ORB_1_4 xorb = (ORB_1_4) orb; + Delegate d = o._get_delegate(); + + if (d instanceof LocalDelegate) + { + LocalDelegate l = (LocalDelegate) d; + poa = l.poa; + } + else if (d instanceof SimpleDelegate) + { + byte[] ior_key = ((SimpleDelegate) d).getIor().key; + AOM.Obj ref = xorb.rootPOA.findIorKey(ior_key); + if (ref != null) + poa = ref.poa; + } + } + } + catch (Exception ex) + { + // OK, POA info is not available, but as ORB is available, we + // will connect in a default way. + } + } + } + catch (Exception ex) + { + RuntimeException rex = new RuntimeException("Unable to get info from " + + a_source); + rex.initCause(ex); + throw rex; + } + + if (!ok && a_source instanceof Tie) + { + Tie t = (Tie) a_source; + orb = t.orb(); + poa = null; + ok = true; + } + + if (orb == null) + throw new RemoteException("Unable to determine ORB from " + a_source); + + if (a_target instanceof Stub) + { + StubDelegateImpl.connect((Stub) a_target, orb, poa); + } + else if (a_target instanceof Servant) + { + try + { + if (poa == null) + { + poa = POAHelper.narrow(orb.resolve_initial_references("RootPOA")); + // Activate if not active. + if (poa.the_POAManager().get_state().value() == State._HOLDING) + poa.the_POAManager().activate(); + } + poa.servant_to_reference((Servant) a_target); + } + catch (Exception ex) + { + throw new Unexpected(ex); + } + } + else if (a_target instanceof org.omg.CORBA.Object) + { + // Connect as object. + orb.connect((org.omg.CORBA.Object) a_target); + } + else if (a_target instanceof Tie) + { + // We avoid calling this because it will aways connect to the root poa. + ((Tie) a_target).orb(orb); + } + } + + /** + * Narrow the given object to the instance of the given class. The currently + * supported narrowing types are: + * + * 1. Simple widening conversion.
    + * 2. ObjectImpl -> RMI interface.
    + * 3. ObjectImpl -> ObjectImpl.
    + * 4. Tie -> Remote (implementation)
    + * 5. Remote (implementation) -> Tie.
    + * + * The narrowing has sense only for derived classes. + */ + public Object narrow(Object narrowFrom, Class narrowTo) + throws ClassCastException + { + if (narrowTo == null) + throw new ClassCastException("Can't narrow to null class"); + else if (narrowFrom == null) + return null; + else + // Simple narrowing case. + if (narrowTo.isAssignableFrom(narrowFrom.getClass())) + return narrowFrom; + else if (narrowTo.isInterface() || narrowFrom instanceof ObjectImpl) + { + // Narrow CORBA object to passed interface. + + String interf = narrowTo.getName(); + String stubClassName; + + stubClassName = getStubClassName(interf); + + try + { + // Replace the interface class by the stub class. + narrowTo = Util.loadClass(stubClassName, null, + narrowTo.getClassLoader()); + } + catch (ClassNotFoundException e) + { + ClassCastException cex = new ClassCastException("Class not found: " + + stubClassName); + cex.initCause(e); + throw cex; + } + } + else if (narrowFrom instanceof Tie) + { + // Try to substitute the return tie target as a return value. + Remote target = ((Tie) narrowFrom).getTarget(); + if (target != null && narrowTo.isAssignableFrom(target.getClass())) + return target; + } + + Object narrowed; + try + { + narrowed = narrowTo.newInstance(); + } + catch (Exception e) + { + ClassCastException cex = new ClassCastException("Cannot instantiate " + + narrowTo.getName()); + cex.initCause(e); + throw cex; + } + + if (narrowed instanceof ObjectImpl) + { + // This also works for the instances of the Stub. + ObjectImpl target = (ObjectImpl) narrowed; + // Set the delegate, as is done in *Helper.narrow(..). + target._set_delegate(((ObjectImpl) narrowFrom)._get_delegate()); + } + else if (narrowed instanceof Tie && narrowFrom instanceof Remote) + { + // Try to set the narrowing object as a target for the Tie. + ((Tie) narrowed).setTarget((Remote) narrowFrom); + } + else + throw new ClassCastException("Narrowing of " + narrowFrom.getClass() + + " to " + narrowTo + " is either not possible or not implemented."); + + return narrowed; + } + + /** + * Get the Stub class name for the name, representing the given interface. + */ + static String getStubClassName(String interf) + { + String stubClassName; + int p = interf.lastIndexOf('.'); + + if (p < 0) + // The interface is defined in the default package. + stubClassName = "_" + interf + "_Stub"; + else + stubClassName = interf.substring(0, p + 1) + "_" + + interf.substring(p + 1) + "_Stub"; + return stubClassName; + } + + /** + * Get stub for the given implementation, searching by class name pattern. The + * found stub must implement Remote for this method to succeed. + */ + public Remote toStub(Remote ObjImpl) + throws NoSuchObjectException + { + String icn = ObjImpl.getClass().getName(); + if (!icn.endsWith("Impl")) + throw new BAD_PARAM("Invalid class name '" + icn + + "', must end with 'Impl'"); + + String sn = "_" + icn.substring(0, icn.length() - "Impl".length()) + + "_Stub"; + + Class stubClass; + Object o_stub; + + try + { + stubClass = RMIClassLoader.loadClass(sn); + o_stub = stubClass.newInstance(); + } + catch (Exception e) + { + NoSuchObjectException n = new NoSuchObjectException(sn); + n.initCause(e); + throw n; + } + + if (!Remote.class.isAssignableFrom(stubClass)) + throw new ClassCastException(stubClass.getName() + + " exists but cannot be returned as it does not inherit from " + + Remote.class.getName()); + + return (Remote) o_stub; + } + + /** + * If the object tie is no longer in use, disconnet it from the orb. + */ + public void unexportObject(Remote obj) + throws NoSuchObjectException + { + Util.unexportObject(obj); + } + + /** + * Find or create a tie for this target and mark it as being used by the given + * object. + */ + public void exportObject(Remote obj) + throws RemoteException + { + if (obj instanceof Stub) + Util.registerTarget(StubDelegateImpl.getTieFromStub((Stub) obj), obj); + else if (obj instanceof Tie) + { + Tie t = (Tie) obj; + Util.registerTarget(t, null); + } + } + +} diff --git a/libjava/classpath/gnu/javax/rmi/CORBA/RmiUtilities.java b/libjava/classpath/gnu/javax/rmi/CORBA/RmiUtilities.java new file mode 100644 index 000000000..ac6b90705 --- /dev/null +++ b/libjava/classpath/gnu/javax/rmi/CORBA/RmiUtilities.java @@ -0,0 +1,949 @@ +/* RmiUtilities.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.rmi.CORBA; + +import gnu.CORBA.OrbFunctional; +import gnu.CORBA.Minor; +import gnu.CORBA.Unexpected; +import gnu.CORBA.CDR.Vio; +import gnu.CORBA.CDR.gnuRuntime; +import gnu.CORBA.CDR.gnuValueStream; +import gnu.CORBA.CDR.HeadlessInput; + +import gnu.java.lang.CPStringBuilder; + +import org.omg.CORBA.MARSHAL; +import org.omg.CORBA.StringValueHelper; +import org.omg.CORBA.WStringValueHelper; +import org.omg.CORBA.portable.Delegate; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.ObjectImpl; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.ValueBase; +import org.omg.PortableServer.POA; +import org.omg.PortableServer.POAHelper; +import org.omg.PortableServer.Servant; +import org.omg.PortableServer.POAManagerPackage.State; +import org.omg.SendingContext.RunTime; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.rmi.Remote; +import java.security.MessageDigest; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Iterator; +import java.util.TreeSet; +import java.util.WeakHashMap; + +import javax.rmi.PortableRemoteObject; +import javax.rmi.CORBA.Stub; +import javax.rmi.CORBA.Tie; +import javax.rmi.CORBA.Util; + +/** + * Defines methods that must be accessible in several derived classes. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class RmiUtilities +{ + /** + * The currently used RMI-IIOP version format. + */ + public static byte VERSION = 1; + + /** + * The non - writable class fields. + */ + static final int NON_WRITABLE = Modifier.STATIC | Modifier.TRANSIENT; + + /** + * The standard String repository Id. + */ + public static final String RMI_STRING_ID = StringValueHelper.id(); + + /** + * The standard Class repository Id. + */ + public static final String RMI_CLASS_ID = "RMI:javax.rmi.CORBA.ClassDesc:2BABDA04587ADCCC:CFBF02CF5294176B"; + + /** + * The standard string array repository Id. + */ + public static final String RMI_STRING_ARRAY_ID = "RMI:[Ljava.lang.String;:071DA8BE7F971128:A0F0A4387A3BB342"; + + /** + * An instance of the wide string value helper for writing strings. + */ + static WStringValueHelper wStringValueHelper = new WStringValueHelper(); + + /** + * Set of serializable classes that have .writeObject and .readObject defined. + * Contains weak references to ensure that the classes will be unloadable. + */ + WeakHashMap io_format = new WeakHashMap(); + + /** + * The standard IO format with no .writeObject and .readObject defined. + */ + static final Object STANDARD = new Object(); + + /** + * The custom IO format with .writeObject and .readObject defined, + * defaultWriteObject called. + */ + static final Object CUSTOM_DWO = new Object(); + + /** + * The custom IO format with .writeObject and .readObject defined, + * defaultWriteObject has not been called. + */ + static final Object CUSTOM_NO_DWO = new Object(); + + /** + * The arguments for readObject. + */ + static final Class[] READ_OBJECT_ARGS = new Class[] { ObjectInputStream.class }; + + /** + * The arguments for writeObject. + */ + static final Class[] WRITE_OBJECT_ARGS = new Class[] { ObjectOutputStream.class }; + + /** + * The undocumented field that is heading the Sun's object data, written with + * writeObject. + */ + static final int S_X = 16908034; + + /** + * Write all fields of the passed value. + */ + void writeFields(OutputStream an_output, Serializable object) + { + org.omg.CORBA_2_3.portable.OutputStream output = (org.omg.CORBA_2_3.portable.OutputStream) an_output; + try + { + Class o_class = object.getClass(); + Field[] fields = getWritableFields(o_class); + Field f; + + Class fc; + + for (int i = 0; i < fields.length; i++) + { + f = fields[i]; + fc = f.getType(); + Object v = f.get(object); + + if (fc == String.class) + { + output.write_value((Serializable) v, wStringValueHelper); + } + else if (fc == int.class) + output.write_long(((Integer) v).intValue()); + else if (fc == long.class) + output.write_longlong(((Number) v).longValue()); + else if (fc == double.class) + output.write_double(((Number) v).doubleValue()); + else if (fc == float.class) + output.write_float(((Number) v).floatValue()); + else if (fc == boolean.class) + output.write_boolean(((Boolean) v).booleanValue()); + else if (fc == short.class) + output.write_short(((Number) v).shortValue()); + else if (fc == byte.class) + output.write_octet(((Number) v).byteValue()); + else if (fc == char.class) + output.write_wchar(((Character) v).charValue()); + else + { + if (!fc.isInterface() && Remote.class.isAssignableFrom(fc)) + fc = getExportedInterface(fc); + writeMember(output, v, fc); + } + } + } + catch (Exception ex) + { + MARSHAL m = new MARSHAL("Cannot write " + object); + m.minor = Minor.ValueFields; + m.initCause(ex); + throw m; + } + } + + /** + * Write a memeber (field) of the data structure. + */ + void writeMember(org.omg.CORBA_2_3.portable.OutputStream output, + Object object, Class xClass) + { + if (output instanceof gnuValueStream) + { + gnuRuntime g = ((gnuValueStream) output).getRunTime(); + // Reset the target as we are already beyond the critical point + // where is must have the value being written. + if (g != null) + g.target = null; + } + if (Serializable.class.isAssignableFrom(xClass) + || Remote.class.isAssignableFrom(xClass)) + { + // Object handles null reference on its own. + if (org.omg.CORBA.Object.class.isAssignableFrom(xClass) + || Remote.class.isAssignableFrom(xClass)) + { + if (object == null) + output.write_Object(null); + else if (isTieRequired(object)) + exportTie(output, object, xClass); + else + writeValue(output, (Serializable) object); + } + else + output.write_value((Serializable) object, xClass); + } + else + { + MARSHAL m = new MARSHAL(xClass + " is not Serializable"); + m.minor = Minor.NonSerializable; + throw m; + } + } + + /** + * Check if the object must be wrapped into Tie, connected to the ORB and then + * the corresponding Stub be written. + */ + public boolean isTieRequired(Object object) + { + return object instanceof Remote && !(object instanceof Stub); + } + + /** + * Get the interface under that the class of this object must be exposed. The + * interface must be derived from Remote. + */ + Class getExportedInterface(Object object) + throws MARSHAL + { + Class fc = null; + Class[] interfaces = object.getClass().getInterfaces(); + for (int i = 0; i < interfaces.length; i++) + { + if (!Remote.class.equals(interfaces[i])) + if (Remote.class.isAssignableFrom(interfaces[i])) + { + if (fc == null) + fc = interfaces[i]; + else + { + MARSHAL m = new MARSHAL("Both " + fc + " and " + interfaces[i] + + " extends Remote"); + m.minor = Minor.TargetConversion; + throw m; + } + } + } + if (fc == null) + { + MARSHAL m = new MARSHAL(object.getClass() + + " does not implement any interface, derived from Remote"); + m.minor = Minor.TargetConversion; + throw m; + } + return fc; + } + + /** + * Get the persistent hash code for the given class, as defined by OMG + * standard. The inheritance, field names and types (but not the visibility) + * are taken into consideration as well as the presence of the writeObject + * method are taken into consideration. The class name and methods, if any, + * are not taken into consideration. + */ + public static long getHashCode(Class c) + { + Class of = c.isArray() ? c.getComponentType() : null; + if (c.isArray() + && ((!Serializable.class.isAssignableFrom(of) || of.isPrimitive() || Remote.class.isAssignableFrom(of)))) + return 0; + if (!Serializable.class.isAssignableFrom(c)) + return 0; + try + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(bout); + + Class superClass = c.getSuperclass(); + if (superClass != null) + out.writeLong(getHashCode(superClass)); + + int writeObjectPresentCode; + try + { + c.getDeclaredMethod("writeObject", + new Class[] { ObjectOutputStream.class }); + writeObjectPresentCode = 2; // Exists. + } + catch (NoSuchMethodException e) + { + writeObjectPresentCode = 1; // Missing. + } + out.writeInt(writeObjectPresentCode); + + Field[] fields = c.getDeclaredFields(); + + Arrays.sort(fields, new Comparator() + { + public int compare(Object a, Object b) + { + Field fa = (Field) a; + Field fb = (Field) b; + return fa.getName().compareTo(fb.getName()); + } + }); + + Field f; + for (int i = 0; i < fields.length; i++) + { + f = fields[i]; + if ((f.getModifiers() & NON_WRITABLE) == 0) + { + out.writeUTF(f.getName()); + out.writeUTF(getDescriptor(f.getType())); + } + } + + out.flush(); + out.close(); + MessageDigest shaDigest; + try + { + shaDigest = MessageDigest.getInstance("SHA"); + } + catch (Exception ex) + { + throw new InternalError("SHA digesting algorithm is not available"); + } + + // Return the digest value to the calling + // method as an array of bytes. + byte[] sha = shaDigest.digest(bout.toByteArray()); + + long hash = 0; + for (int i = 0; i < Math.min(8, sha.length); i++) + { + hash += (long) (sha[i] & 255) << (i * 8); + } + return hash; + } + catch (IOException ioex) + { + throw new Unexpected(ioex); + } + } + + /** + * Converts to hexadecimal string, supplementing leading zeros. + */ + public static String toHex(long l) + { + CPStringBuilder b = new CPStringBuilder(); + b.append(Long.toHexString(l).toUpperCase()); + while (b.length() < 16) + b.insert(0, '0'); + return b.toString(); + } + + /** + * Returns a String representing the type-encoding of a class. + */ + static String getDescriptor(Class type) + { + if (type.equals(boolean.class)) + return "Z"; + if (type.equals(byte.class)) + return "B"; + if (type.equals(short.class)) + return "S"; + if (type.equals(char.class)) + return "C"; + if (type.equals(int.class)) + return "I"; + if (type.equals(long.class)) + return "J"; + if (type.equals(float.class)) + return "F"; + if (type.equals(double.class)) + return "D"; + if (type.equals(void.class)) + return "V"; + else if (type.isArray()) + { + CPStringBuilder l = new CPStringBuilder("["); + Class component = type.getComponentType(); + + while (component.isArray()) + { + l.append('['); + component = component.getComponentType(); + } + + l.append('L'); + l.append(component.getName().replace('.', '/')); + l.append(';'); + return l.toString(); + } + else + return "L" + type.getName().replace('.', '/') + ';'; + } + + public static Field[] getWritableFields(Class c) + { + TreeSet set = new TreeSet(new Comparator() + { + public int compare(Object a, Object b) + { + return ((Field) a).getName().compareTo(((Field) b).getName()); + } + }); + + while (!c.equals(Object.class)) + { + Field[] f = c.getDeclaredFields(); + for (int i = 0; i < f.length; i++) + { + if ((f[i].getModifiers() & NON_WRITABLE) == 0) + { + f[i].setAccessible(true); + set.add(f[i]); + } + } + c = c.getSuperclass(); + } + + Field[] r = new Field[set.size()]; + int p = 0; + Iterator it = set.iterator(); + while (it.hasNext()) + { + r[p++] = (Field) it.next(); + } + return r; + } + + /** + * The method is called for Remotes that are not Stubs. It is assumed, that + * the Remote is an implementation. The method searches for the suitable tie + * and, if found, exports it by creating and connecting the stub. Such export + * is supported since jdk 1.5. + */ + void exportTie(org.omg.CORBA_2_3.portable.OutputStream output, + Object implementation, Class interfaceClass) + { + try + { + // Remote, but non - stub class (implementation) + // must be replaced by stub. + Tie t = Util.getTie((Remote) implementation); + if (t instanceof Servant) + { + POA rootPoa = POAHelper.narrow(output.orb().resolve_initial_references( + "RootPOA")); + org.omg.CORBA.Object co = rootPoa.servant_to_reference((Servant) t); + Stub stub = (Stub) PortableRemoteObject.narrow(co, interfaceClass); + writeRemoteObject(output, stub); + + if (rootPoa.the_POAManager().get_state().value() == State._HOLDING) + rootPoa.the_POAManager().activate(); + } + else if (t instanceof org.omg.CORBA.Object) + { + org.omg.CORBA.Object co = (org.omg.CORBA.Object) t; + output.orb().connect(co); + + Stub stub = (Stub) PortableRemoteObject.narrow(co, interfaceClass); + writeRemoteObject(output, stub); + } + } + catch (Exception ex) + { + MARSHAL m = new MARSHAL("Unable to export " + implementation); + m.minor = Minor.TargetConversion; + m.initCause(ex); + throw m; + } + } + + /** + * Start the ORB, if it is not already runnning. + */ + void ensureOrbRunning(org.omg.CORBA_2_3.portable.OutputStream output) + { + // Ensure ORB is running. + if (output.orb() instanceof OrbFunctional) + { + ((OrbFunctional) output.orb()).ensureRunning(); + } + } + + /** + * Write data to the CORBA output stream. Writes the object contents only; the + * header must be already written. For object, containing objects, may be + * called recursively. + * + * @param an_output a stream to write to, must be + * org.omg.CORBA_2_3.portable.OutputStream + * @param object an object to write. + */ + public void writeRemoteObject(OutputStream an_output, Object object) + { + org.omg.CORBA_2_3.portable.OutputStream output = (org.omg.CORBA_2_3.portable.OutputStream) an_output; + + if (isTieRequired(object)) + { + // Find the interface that is implemented by the object and extends + // Remote. + Class fc = getExportedInterface(object); + exportTie(output, object, fc); + } + else if (object instanceof org.omg.CORBA.Object) + { + ensureOrbRunning(output); + an_output.write_Object((org.omg.CORBA.Object) object); + } + else if (object != null && object instanceof Serializable) + writeFields(an_output, (Serializable) object); + } + + /** + * Write data to the CORBA output stream. Writes the object contents only; the + * header must be already written. For object, containing objects, may be + * called recursively. + * + * @param an_output a stream to write to, must be + * org.omg.CORBA_2_3.portable.OutputStream + * @param object an object to write. + */ + public void writeValue(OutputStream an_output, Serializable object) + { + org.omg.CORBA_2_3.portable.OutputStream output = (org.omg.CORBA_2_3.portable.OutputStream) an_output; + + if (isTieRequired(object)) + { + // Find the interface that is implemented by the object and extends + // Remote. + Class fc = getExportedInterface(object); + exportTie(output, object, fc); + } + else if (object instanceof org.omg.CORBA.Object) + { + ensureOrbRunning(output); + an_output.write_Object((org.omg.CORBA.Object) object); + } + else if (object instanceof Externalizable) + { + try + { + ObjectOutputStream stream = new CorbaOutput(output, object, + this); + stream.write(VERSION); + ((Externalizable) object).writeExternal(stream); + } + catch (Exception ex) + { + MARSHAL m = new MARSHAL("writeExternal failed"); + m.minor = Minor.Value; + m.initCause(ex); + throw m; + } + } + else if (object instanceof Serializable) + { + Object mode = null; + synchronized (io_format) + { + mode = io_format.get(object.getClass()); + if (mode == STANDARD) + { + writeFields(an_output, (Serializable) object); + return; + } + } + try + { + Method m = object.getClass().getDeclaredMethod("writeObject", + WRITE_OBJECT_ARGS); + m.setAccessible(true); // May be private. + + try + { + ObjectOutputStream stream = new CorbaOutput(output, + object, this); + + // Write version. + stream.write(VERSION); + + if (mode == CUSTOM_DWO) + // Write true, supposing that the defaultWriteObject + // has been called. + stream.write(1); + else if (mode == CUSTOM_NO_DWO) + // Write false (has not been called) + stream.write(0); + else + { + // Measure. + DefaultWriteObjectTester tester = new DefaultWriteObjectTester(object); + m.invoke(object, new Object[] { tester }); + + synchronized (io_format) + { + io_format.put(object.getClass(), + tester.dwo_called ? CUSTOM_DWO : CUSTOM_NO_DWO); + stream.write(tester.dwo_called ? 1 : 0); + } + } + + m.invoke(object, new Object[] { stream }); + stream.flush(); + } + catch (Exception ex) + { + MARSHAL mx = new MARSHAL(object.getClass().getName() + + ".writeObject failed"); + mx.initCause(ex); + throw mx; + } + } + catch (NoSuchMethodException e) + { + // Write in a standard way. + writeFields(an_output, (Serializable) object); + synchronized (io_format) + { + io_format.put(object.getClass(), STANDARD); + } + } + } + } + + /** + * Read data from the CDR input stream. Reads the object contents only; the + * header must be already read (the repository id or ids ara passed). For + * object, containing objects, may be called recursively. + * + * @param an_input the stream to read from, must be + * org.omg.CORBA_2_3.portable.InputStream + * @param object the instance of the object being read. + * @param id the repository Id from the stream in the case when single id was + * specified. + * @param ids the repository Ids from the stream in the case when multiple ids + * were specified. + * @param codebase the codebase, if it was included in the header of the value + * type. Null if not codebase was included. + * + * @return the object, extracted from the stream. + */ + /** + * Read value from the input stream in the case when the value is not + * Streamable or CustomMarshalled. + */ + public Serializable readValue(InputStream in, int offset, Class clz, + String repositoryID, RunTime sender) + { + if (in instanceof HeadlessInput) + ((HeadlessInput) in).subsequentCalls = true; + + gnuRuntime g = null; + Serializable object = null; + + try + { + g = (gnuRuntime) sender; + if (sender != null) + object = g.target; + } + catch (ClassCastException e) + { + // Working with the other CORBA implementation. + g = null; + } + + org.omg.CORBA_2_3.portable.InputStream input = (org.omg.CORBA_2_3.portable.InputStream) in; + + if (Remote.class.isAssignableFrom(clz) + || ValueBase.class.isAssignableFrom(clz)) + { + // Interface is narrowed into Stub. + if (clz.isInterface()) + try + { + clz = Util.loadClass( + PortableRemoteObjectDelegateImpl.getStubClassName(clz.getName()), + null, clz.getClassLoader()); + } + catch (ClassNotFoundException e) + { + MARSHAL m = new MARSHAL("Cannot get stub from interface " + + clz.getClass().getName()); + m.minor = Minor.TargetConversion; + m.initCause(e); + throw m; + } + + // Remote needs special handling. + if (ObjectImpl.class.isAssignableFrom(clz)) + { + // First read CORBA object reference. + Object ro = input.read_Object(); + + ObjectImpl obj = (ObjectImpl) ro; + if (obj == null) + return null; + + Delegate delegate = obj._get_delegate(); + object = instantiate(offset, clz, g); + ((ObjectImpl) object)._set_delegate(delegate); + } + // The object - specific data follows. + } + else if (org.omg.CORBA.Object.class.isAssignableFrom(clz)) + object = (Serializable) input.read_Object(); + + if (object == null) + object = instantiate(offset, clz, g); + + // The sentence below prevents attempt to read the internal fields of the + // ObjectImpl (or RMI Stub) that might follow the object definition. + // Sun's jre 1.5 does not write this information. The stubs, generated + // by rmic, does not contain such fields. + if (object instanceof ObjectImpl) + return object; + + if (object instanceof Externalizable) + { + try + { + CorbaInput stream = new CorbaInput(input, object, this, + offset, repositoryID, g); + + byte version = stream.readByte(); + if (version != 1) + throw new MARSHAL("Unsuported RMI-IIOP version " + version); + + ((Externalizable) object).readExternal(stream); + } + catch (Exception ex) + { + MARSHAL m = new MARSHAL("readExternal failed"); + m.initCause(ex); + throw m; + } + } + else + { + Object mode = null; + synchronized (io_format) + { + mode = io_format.get(object.getClass()); + } + + if (mode == STANDARD) + { + readFields(offset, repositoryID, object, input, g); + } + else + { + try + { + Method m = object.getClass().getDeclaredMethod("readObject", + READ_OBJECT_ARGS); + try + { + m.setAccessible(true); // May be private. + + CorbaInput stream = new CorbaInput(input, + object, this, offset, repositoryID, g); + + byte version = stream.readByte(); + if (version != 1) + throw new MARSHAL("Unsuported RMI-IIOP version " + + version); + + // This would indicate is defaultWriteObject has been + // called, + // but the readObject method normally takes care about this. + boolean dwo = stream.readByte() != 0; + + m.invoke(object, new Object[] { stream }); + synchronized (io_format) + { + io_format.put(object.getClass(), dwo ? CUSTOM_DWO + : CUSTOM_NO_DWO); + } + } + catch (Exception ex) + { + ex.printStackTrace(); + MARSHAL mx = new MARSHAL(object.getClass().getName() + + ".readObject failed"); + mx.initCause(ex); + throw mx; + } + } + catch (NoSuchMethodException e) + { + // Read in a standard way. + synchronized (io_format) + { + io_format.put(object.getClass(), STANDARD); + readFields(offset, repositoryID, object, input, g); + } + } + } + } + return object; + } + + /** + * Create an instance. + */ + Serializable instantiate(int offset, Class clz, gnuRuntime g) + throws MARSHAL + { + Serializable object; + try + { + object = (Serializable) Vio.instantiateAnyWay(clz); + g.objectWritten(object, offset); + } + catch (Exception e) + { + MARSHAL m = new MARSHAL("Unable to instantiate " + clz); + m.minor = Minor.Instantiation; + m.initCause(e); + throw m; + } + return object; + } + + /** + * Read fields of the object. + */ + void readFields(int offset, String repositoryID, Serializable object, + org.omg.CORBA_2_3.portable.InputStream input, gnuRuntime r) + throws MARSHAL + { + Field f = null; + Class o_class = object.getClass(); + + try + { + // The returned field array must already be in canonical order. + Field[] fields = getWritableFields(o_class); + + Class fc; + + for (int i = 0; i < fields.length; i++) + { + // Full value type header expected ahead. + if (input instanceof HeadlessInput) + ((HeadlessInput) input).subsequentCalls = true; + + f = fields[i]; + fc = f.getType(); + + Object v; + + if (fc == String.class) + { + v = input.read_value(wStringValueHelper); + } + else if (fc == int.class) + v = new Integer(input.read_long()); + else if (fc == long.class) + v = new Long(input.read_longlong()); + else if (fc == double.class) + v = new Double(input.read_double()); + else if (fc == float.class) + v = new Float(input.read_float()); + else if (fc == boolean.class) + v = input.read_boolean() ? Boolean.TRUE : Boolean.FALSE; + else if (fc == short.class) + v = new Short(input.read_short()); + else if (fc == byte.class) + v = new Byte(input.read_octet()); + else if (fc == char.class) + v = new Character(input.read_char()); + else if (org.omg.CORBA.Object.class.isAssignableFrom(fc) + || Remote.class.isAssignableFrom(fc)) + { + v = readValue(input, offset, fc, null, r); + } + else + { + v = Vio.read(input, fc); + } + + f.set(object, v); + } + } + catch (Exception ex) + { + MARSHAL m = new MARSHAL("Cannot read " + o_class.getName() + " field " + + f); + m.initCause(ex); + m.minor = Minor.ValueFields; + throw m; + } + } + +} diff --git a/libjava/classpath/gnu/javax/rmi/CORBA/StubDelegateImpl.java b/libjava/classpath/gnu/javax/rmi/CORBA/StubDelegateImpl.java new file mode 100644 index 000000000..05c73a709 --- /dev/null +++ b/libjava/classpath/gnu/javax/rmi/CORBA/StubDelegateImpl.java @@ -0,0 +1,310 @@ +/* StubDelegateImpl.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.rmi.CORBA; + +import gnu.CORBA.ObjectCreator; +import gnu.CORBA.Unexpected; +import gnu.CORBA.CDR.BufferredCdrInput; +import gnu.CORBA.CDR.BufferedCdrOutput; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.rmi.Remote; +import java.rmi.RemoteException; + +import javax.rmi.PortableRemoteObject; +import javax.rmi.CORBA.Stub; +import javax.rmi.CORBA.StubDelegate; +import javax.rmi.CORBA.Tie; +import javax.rmi.CORBA.Util; + +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.ORB; +import org.omg.CORBA.portable.Delegate; +import org.omg.CORBA.portable.ObjectImpl; +import org.omg.PortableServer.POA; +import org.omg.PortableServer.POAHelper; +import org.omg.PortableServer.Servant; +import org.omg.PortableServer.POAManagerPackage.State; + +/** + * The default stub delegate. + * + * @author Wu Gansha (gansha.wu@intel.com) (stub) + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) (implementation) + */ +public class StubDelegateImpl + implements StubDelegate +{ + /** + *

    + * Finds the suitable {@link Tie} for this Stub and connects it to the given + * ORB. The tie is found by the name pattern. If the found tie is derived from + * {@link org.omg.CORBA.PortableServer.Servant}, it is connected to the root + * POA, also activating it (if not already active). + *

    + *

    + * This method does not allow to specify, to which POA the found Tie must be + * connected and requires to use the deprecated method {@link ORB#connect}. + * Many useful POA features remain unaccessible. A better alternative it might + * be to generate a {@link org.omg.CORBA.PortableServer.Servant} - derived Tie + * (-poa key in rmic) and connect it to POA in one of the many ways, listed in + * the description of the {@link orb.omg.PortableServer} package). The + * obtained CORBA object can be narrowed into stub using + * {@link PortableRemoteObject#narrow}. + *

    + * + * @param orb the ORB where the Stub must be connected. + * + * @throws RemoteException if the stub is already connected to some other ORB. + * If the stub is already connected to the ORB that was passed as parameter, + * the method returns without action. + * + * @throws BAD_PARAM if the name of this stub does not match the stub name + * pattern, "_*_Stub" or if the Tie class, "_*Impl_Tie", does not exists or an + * instance of this class cannot be instantiated. + */ + public void connect(Stub self, ORB orb) + throws RemoteException + { + connect(self, orb, null); + } + + /** + * Connect when the POA is specified. + */ + public static void connect(Stub self, ORB orb, POA poa) + throws RemoteException + { + ORB oorb = null; + try + { + Delegate d = self._get_delegate(); + if (d != null) + oorb = d.orb(self); + } + catch (Exception e) + { + // Failed to get Delegate or ORB. + // (possible ony for user-written Stubs). + } + + if (oorb != null) + { + if (!oorb.equals(orb)) + throw new RemoteException("Stub " + self + + " is connected to another ORB, " + orb); + else + return; + } + + Tie t = null; + if (self instanceof Remote) + t = Util.getTie((Remote) self); + + // Find by name pattern. + if (t == null) + t = getTieFromStub(self); + + Delegate delegate; + + if (t instanceof Servant) + { + try + { + if (poa == null) + { + poa = POAHelper.narrow(orb.resolve_initial_references("RootPOA")); + // Activate if not active. + if (poa.the_POAManager().get_state().value() == State._HOLDING) + poa.the_POAManager().activate(); + } + + ObjectImpl obj = (ObjectImpl) poa.servant_to_reference((Servant) t); + delegate = obj._get_delegate(); + } + catch (Exception ex) + { + throw new Unexpected(ex); + } + } + else if (t instanceof ObjectImpl) + { + ObjectImpl o = (ObjectImpl) t; + orb.connect(o); + delegate = o._get_delegate(); + } + else + throw new BAD_PARAM("The Tie must be either Servant or ObjectImpl"); + + self._set_delegate(delegate); + } + + /** + * Locate a tie class, appropriate to the given stub class, by the name + * pattern. + */ + public static Tie getTieFromStub(java.lang.Object self) + { + Tie t; + String sn = self.getClass().getName(); + if (!sn.endsWith("_Stub")) + throw new BAD_PARAM("The stub name, " + sn + + ", does not match _*_Stub pattern"); + + String tn = sn.substring(0, sn.length() - "_Stub".length()) + "Impl_Tie"; + Class tieClass = null; + + try + { + tieClass = ObjectCreator.forName(tn); + t = (Tie) tieClass.newInstance(); + if (self instanceof Remote) + Util.registerTarget(t, (Remote) self); + } + catch (Exception e) + { + BAD_PARAM bad = new BAD_PARAM("Unable to instantiate '" + tn + "'"); + bad.initCause(e); + throw bad; + } + return t; + } + + /** + * Compare two stubs for equality. + */ + public boolean equals(Stub self, java.lang.Object obj) + { + if (obj instanceof ObjectImpl) + { + ObjectImpl other = (ObjectImpl) obj; + Delegate d1 = other._get_delegate(); + Delegate d2 = self._get_delegate(); + if (d1 == null || d2 == null) + return d1 == d2; + else + return d1.equals(d2); + } + else return false; + } + + /** + * Get the hash code (from IOR reference). + */ + public int hashCode(Stub self) + { + Delegate d = self._get_delegate(); + return d==null?0:d.hashCode(); + } + + /** + * Returns the IOR reference of the connected ORB. + * + * @see ORB#object_to_string(org.omg.CORBA.Object); + */ + public String toString(Stub self) + { + try + { + return self._orb().object_to_string(self); + } + catch (Exception ex) + { + return null; + } + } + + /** + * This should never be called. The ORB must be supplied. + * + * @see #connect + */ + public void readObject(Stub self, ObjectInputStream input) + throws IOException, ClassNotFoundException + { + readObject(self, input, null); + } + + /** + * Read as CORBA object when the ORB is known. The ORB must be set under the + * previous call of Stub.connect. The Stub is automatically registered with + * this ORB. + */ + public void readObject(Stub self, ObjectInputStream input, ORB orb) + throws IOException, ClassNotFoundException + { + byte[] b = (byte[]) input.readObject(); + BufferredCdrInput in = new BufferredCdrInput(b); + + if (orb != null) + in.setOrb(orb); + + ObjectImpl r = (ObjectImpl) in.read_Object(); + + self._set_delegate(r._get_delegate()); + } + + /** + * Write as CORBA object. The ORB is taken from the + * org.omg.CORBA.portable.Delegate. The Stub is automatically registered with + * this ORB (if not already done). + */ + public void writeObject(Stub self, ObjectOutputStream output) + throws IOException + { + writeObject(self, output, null); + } + + /** + * Write as CORBA object. The ORB must be either set under the previous call + * of Stub.connect or it is taken from the org.omg.CORBA.portable.Delegate. + * The Stub is automatically registered with this ORB (if not already done). + */ + public void writeObject(Stub self, ObjectOutputStream output, ORB orb) + throws IOException + { + BufferedCdrOutput out = new BufferedCdrOutput(); + out.setOrb(orb == null ? self._orb() : orb); + out.write_Object(self); + + output.writeObject(out.buffer.toByteArray()); + } +} diff --git a/libjava/classpath/gnu/javax/rmi/CORBA/TieTargetRecord.java b/libjava/classpath/gnu/javax/rmi/CORBA/TieTargetRecord.java new file mode 100644 index 000000000..f39441e38 --- /dev/null +++ b/libjava/classpath/gnu/javax/rmi/CORBA/TieTargetRecord.java @@ -0,0 +1,93 @@ +/* TieTargetRecord.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.rmi.CORBA; + +import java.util.HashSet; + +import javax.rmi.CORBA.Tie; + +/** + * Represents a Tie, connected to possibly multiple invocation targets. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class TieTargetRecord +{ + /** + * The associated Tie. + */ + public final Tie tie; + + /** + * The objects, exposing the tie. + */ + public HashSet targets = new HashSet(); + + /** + * Create a new record. + */ + public TieTargetRecord(Tie a_tie) + { + tie = a_tie; + } + + /** + * Add a target. + */ + public void add(Object target) + { + targets.add(target); + } + + /** + * Remove target. + */ + public void remove(Object target) + { + targets.remove(target); + } + + /** + * Return true if the tie has no associated invocation targets. + */ + public boolean unused() + { + return targets.size() == 0; + } +} diff --git a/libjava/classpath/gnu/javax/rmi/CORBA/UtilDelegateImpl.java b/libjava/classpath/gnu/javax/rmi/CORBA/UtilDelegateImpl.java new file mode 100644 index 000000000..dd4e347f2 --- /dev/null +++ b/libjava/classpath/gnu/javax/rmi/CORBA/UtilDelegateImpl.java @@ -0,0 +1,744 @@ +/* UtilDelegateImpl.java -- + Copyright (C) 2002, 2005, 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.rmi.CORBA; + +import gnu.classpath.VMStackWalker; + +import gnu.CORBA.Minor; +import gnu.CORBA.ObjectCreator; +import gnu.CORBA.Poa.ORB_1_4; +import gnu.CORBA.Poa.AOM; +import gnu.CORBA.Poa.gnuPOA; +import gnu.CORBA.typecodes.GeneralTypeCode; + +import org.omg.CORBA.Any; +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.COMM_FAILURE; +import org.omg.CORBA.CompletionStatus; +import org.omg.CORBA.INVALID_TRANSACTION; +import org.omg.CORBA.INV_OBJREF; +import org.omg.CORBA.MARSHAL; +import org.omg.CORBA.NO_PERMISSION; +import org.omg.CORBA.OBJECT_NOT_EXIST; +import org.omg.CORBA.OMGVMCID; +import org.omg.CORBA.ORB; +import org.omg.CORBA.SystemException; +import org.omg.CORBA.TCKind; +import org.omg.CORBA.TRANSACTION_REQUIRED; +import org.omg.CORBA.TRANSACTION_ROLLEDBACK; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.UNKNOWN; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.net.MalformedURLException; +import java.rmi.AccessException; +import java.rmi.MarshalException; +import java.rmi.NoSuchObjectException; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.ServerError; +import java.rmi.ServerException; +import java.rmi.UnexpectedException; +import java.rmi.server.RMIClassLoader; +import java.util.Hashtable; + +import javax.rmi.CORBA.Stub; +import javax.rmi.CORBA.Tie; +import javax.rmi.CORBA.Util; +import javax.rmi.CORBA.UtilDelegate; +import javax.rmi.CORBA.ValueHandler; +import javax.transaction.InvalidTransactionException; +import javax.transaction.TransactionRequiredException; +import javax.transaction.TransactionRolledbackException; + +/** + * The implementation of UtilDelegate. + * + * @author Wu Gansha (gansha.wu@intel.com) (stub) + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) (implementation) + */ +public class UtilDelegateImpl + extends RmiUtilities + implements UtilDelegate +{ + /** + * The instance of the value handler, requested once. + */ + static ValueHandler m_ValueHandler; + + /** + * The global map of all ties to they records. + */ + static Hashtable m_Ties = new Hashtable(); + + /** + * The global map of all targets to they records. + */ + static Hashtable m_Targets = new Hashtable(); + + /** + * The standard package for that the exception names are omitted. + */ + static final String m_StandardPackage = "org.omg.CORBA."; + + /** + * Make a deep copy of the object. + */ + public Object copyObject(Object obj, ORB orb) + throws RemoteException + { + // Strings are immutable, can be shared. + if (obj instanceof String) + return obj; + else if (obj == null) + return null; + else if (obj instanceof String[] || obj instanceof String[][] + || obj instanceof String[][][]) + { + // String arrays can be just cloned. + return ((Object[]) obj).clone(); + } + else if (obj instanceof Serializable) + { + try + { + ByteArrayOutputStream a = new ByteArrayOutputStream(); + ObjectOutputStream ou = new ObjectOutputStream(a); + ou.writeObject(obj); + ou.close(); + ObjectInputStream input = new ObjectInputStream( + new ByteArrayInputStream(a.toByteArray())); + return input.readObject(); + } + catch (Exception ex) + { + RemoteException rex = new RemoteException("Cannot copy " + obj); + throw rex; + } + } + else + return obj; + } + + /** + * Make a deep copy of the object array. + */ + public Object[] copyObjects(Object[] obj, ORB orb) + throws RemoteException + { + return (Object[]) copyObject(obj, orb); + } + + public ValueHandler createValueHandler() + { + if (m_ValueHandler == null) + m_ValueHandler = (ValueHandler) DelegateFactory.getInstance(DelegateFactory.VALUEHANDLER); + return m_ValueHandler; + } + + /** + * Returns the codebase of the given class. + */ + public String getCodebase(Class clz) + { + return RMIClassLoader.getClassAnnotation(clz); + } + + /** + * Get the Tie that handles invocations on the given target. If the target/Tie + * pair has not been previously registered using {@link #registerTarget}, + * this method tries to locate a tie class by the name pattern. If this + * succeeds, the tie-target pair is also registered. + * + * @return the Tie. + */ + public Tie getTie(Remote target) + { + synchronized (m_Targets) + { + Tie tie; + TieTargetRecord r = ((TieTargetRecord) m_Targets.get(target)); + if (r == null) + { + if (target instanceof Stub) + { + tie = StubDelegateImpl.getTieFromStub(target); + registerTarget(tie, target); + } + else + { + // Treat this as implementation. + String tieClassName = getTieClassName(target.getClass().getName()); + try + { + Class tieClass = Util.loadClass(tieClassName, null, + target.getClass().getClassLoader()); + tie = (Tie) tieClass.newInstance(); + } + catch (Exception e) + { + MARSHAL m = new MARSHAL("Unable to instantiate " + + tieClassName); + m.minor = Minor.TargetConversion; + m.initCause(e); + throw m; + } + tie.setTarget(target); + registerTarget(tie, target); + } + } + else + tie = r.tie; + return tie; + } + } + + /** + * Get the Stub class name for the name, representing the given interface. + */ + private String getTieClassName(String interf) + { + String stubClassName; + int p = interf.lastIndexOf('.'); + + if (p < 0) + // The interface is defined in the default package. + stubClassName = "_" + interf + "_Tie"; + else + stubClassName = interf.substring(0, p + 1) + "_" + + interf.substring(p + 1) + "_Tie"; + return stubClassName; + } + + /** + * Register the Tie-target pair. As the Tie is a Servant, it can potentially + * be connected to several objects and hence may be registered with several + * targets. + */ + public void registerTarget(Tie tie, Remote target) + { + synchronized (m_Ties) + { + synchronized (m_Targets) + { + TieTargetRecord r = (TieTargetRecord) m_Ties.get(tie); + if (r == null) + { + // First registration for this Tie. + r = new TieTargetRecord(tie); + m_Ties.put(tie, r); + } + if (target != null) + { + r.add(target); + m_Targets.put(target, r); + } + } + } + } + + /** + * Deactivate the associated Tie, if it is found and is not connected to other + * registered targets. Independing from the POA policies, the transparent + * reactivation will not be possible. + */ + public void unexportObject(Remote target) + throws NoSuchObjectException + { + synchronized (m_Ties) + { + synchronized (m_Targets) + { + TieTargetRecord r = ((TieTargetRecord) m_Targets.get(target)); + if (r != null) + { + if (target instanceof org.omg.CORBA.Object) + r.tie.orb().disconnect((org.omg.CORBA.Object) target); + + if (r.unused()) + { + m_Targets.remove(target); + m_Ties.remove(r.tie); + r.tie.deactivate(); + + if (r.tie.orb() instanceof ORB_1_4) + { + // Standard case, when more deep cleanup is possible. + // Independing from the POA policies, the object will + // not be activable transparently. + ORB_1_4 orb = (ORB_1_4) r.tie.orb(); + + if (target instanceof org.omg.CORBA.Object) + { + AOM.Obj record = orb.rootPOA.findObject((org.omg.CORBA.Object) target); + + if (record != null && record.servant == r.tie + && record.poa instanceof gnuPOA) + { + ((gnuPOA) record.poa).aom.remove(record.key); + record.deactivated = true; + record.servant = null; + } + } + } + } + } + } + } + } + + /** + * Checks if the given stub is local. + * + * @param stub a stub to check. + * @return true if the stub is local, false otherwise. + */ + public boolean isLocal(Stub stub) + throws RemoteException + { + try + { + return stub._is_local(); + } + catch (SystemException e) + { + RemoteException rex = new RemoteException(); + rex.initCause(e); + throw rex; + } + } + + /** + * Load the class. The method uses class loaders from the call stact first. If + * this fails, the further behaviour depends on the System Property + * "java.rmi.server.useCodebaseOnly" with default value "false". + * + *
      + *
    • Try the current thread context class loader first.
    • + *
    • If remoteCodebase is non-null and useCodebaseOnly is "false" then call + * java.rmi.server.RMIClassLoader.loadClass (remoteCodebase, className)
    • + *
    • If remoteCodebase is null or useCodebaseOnly is true then call + * java.rmi.server.RMIClassLoader.loadClass(className)
    • + *
    • If a class is still not successfully loaded and the loader != null + * then try Class.forName(className, false, loader).
    • + *
    + * + * @param className the name of the class. + * @param remoteCodebase the codebase. + * @param loader the class loader. + * @return the loaded class. + * + * @throws ClassNotFoundException of the class cannot be loaded. + */ + public Class loadClass(String className, String remoteCodebase, + ClassLoader loader) + throws ClassNotFoundException + { + if (loader == null) + loader = VMStackWalker.firstNonNullClassLoader(); + + String p_useCodebaseOnly = System.getProperty("java.rmi.server.useCodebaseOnly"); + + boolean useCodebaseOnly = p_useCodebaseOnly != null + && p_useCodebaseOnly.trim().equalsIgnoreCase("true"); + + if (useCodebaseOnly) + remoteCodebase = null; + + try + { + return RMIClassLoader.loadClass(remoteCodebase, className, loader); + } + catch (MalformedURLException x) + { + throw new ClassNotFoundException(className, x); + } + } + + /** + * Converts CORBA {@link SystemException} into RMI {@link RemoteException}. + * The exception is converted as defined in the following table: + *

    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    CORBA ExceptionRMI Exception
    {@link COMM_FAILURE}{@link MarshalException}
    {@link INV_OBJREF}{@link NoSuchObjectException}
    {@link NO_PERMISSION}{@link AccessException}
    {@link MARSHAL}{@link MarshalException}
    {@link BAD_PARAM} (all other cases){@link MarshalException}
    {@link OBJECT_NOT_EXIST}{@link NoSuchObjectException}
    {@link TRANSACTION_REQUIRED}{@link TransactionRequiredException}
    {@link TRANSACTION_ROLLEDBACK}{@link TransactionRolledbackException}
    {@link INVALID_TRANSACTION}{@link InvalidTransactionException}
    Any other {@link SystemException}{@link RemoteException}
    + *

    + *

    + * The exception detailed message always consists of + *

      + *
    1. the string "CORBA "
    2. + *
    3. the CORBA name of the system exception
    4. + *
    5. single space
    6. + *
    7. the hexadecimal value of the system exception's minor code, preceeded + * by 0x (higher bits contain {@link OMGVMCID}).
    8. + *
    9. single space
    10. + *
    11. the {@link CompletionStatus} of the exception: "Yes", "No" or "Maybe".
    12. + *
    + *

    + * For instance, if the Internet connection was refused: + *

    + *

    + *

    +   * CORBA COMM_FAILURE 0x535500C9 No
    +   * 

    + *

    + * The original CORBA exception is set as the cause of the RemoteException + * being created. + *

    + */ + public RemoteException mapSystemException(SystemException ex) + { + RemoteException rex; + + String status; + + switch (ex.completed.value()) + { + case CompletionStatus._COMPLETED_MAYBE: + status = "Maybe"; + break; + + case CompletionStatus._COMPLETED_NO: + status = "No"; + break; + + case CompletionStatus._COMPLETED_YES: + status = "Yes"; + break; + + default: + status = "Unexpected completion status " + ex.completed.value(); + } + + String name = ex.getClass().getName(); + + if (name.startsWith(m_StandardPackage)) + name = name.substring(m_StandardPackage.length()); + + String message = "CORBA " + name + " 0x" + Integer.toHexString(ex.minor) + + " " + status; + + if (ex instanceof COMM_FAILURE) + rex = new MarshalException(message, ex); + else if (ex instanceof INV_OBJREF) + { + rex = new NoSuchObjectException(message); + rex.detail = ex; + } + else if (ex instanceof NO_PERMISSION) + rex = new AccessException(message, ex); + else if (ex instanceof MARSHAL) + rex = new MarshalException(message, ex); + else if (ex instanceof BAD_PARAM) + rex = new MarshalException(message, ex); + else if (ex instanceof OBJECT_NOT_EXIST) + { + rex = new NoSuchObjectException(message); + rex.detail = ex; + } + else if (ex instanceof TRANSACTION_REQUIRED) + { + rex = new TransactionRequiredException(message); + rex.detail = ex; + } + else if (ex instanceof TRANSACTION_ROLLEDBACK) + { + rex = new TransactionRolledbackException(message); + rex.detail = ex; + } + else if (ex instanceof INVALID_TRANSACTION) + { + rex = new InvalidTransactionException(message); + rex.detail = ex; + } + else if (ex instanceof UNKNOWN) + rex = wrapException(ex.getCause()); + else + rex = new RemoteException(message, ex); + + return rex; + } + + /** + * Converts the exception that was thrown by the implementation method on a + * server side into RemoteException that can be transferred and re-thrown on a + * client side. The method converts exceptions as defined in the following + * table: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Exception to map (or subclass)Maps into
    {@link Error}{@link ServerError}
    {@link RemoteException}{@link ServerException}
    {@link SystemException}wrapException({@link #mapSystemException})
    {@link RuntimeException}rethrows
    Any other exception{@link UnexpectedException}
    + * + * @param ex an exception that was thrown on a server side implementation. + * + * @return the corresponding RemoteException unless it is a RuntimeException. + * + * @throws RuntimeException the passed exception if it is an instance of + * RuntimeException. + * + * @specnote It is the same behavior, as in Suns implementations 1.4.0-1.5.0. + */ + public RemoteException wrapException(Throwable ex) + throws RuntimeException + { + if (ex instanceof RuntimeException) + throw (RuntimeException) ex; + else if (ex instanceof Error) + return new ServerError(ex.getMessage(), (Error) ex); + else if (ex instanceof RemoteException) + return new ServerException(ex.getMessage(), (Exception) ex); + else if (ex instanceof SystemException) + return wrapException(mapSystemException((SystemException) ex)); + else + return new UnexpectedException("Unexpected", (Exception) ex); + } + + /** + * Write abstract interface to the CORBA output stream. The write format is + * matching CORBA abstract interface. Remotes and CORBA objects are written as + * objects, other classes are supposed to be value types and are written as + * such. {@link Remote}s are processed as defined in + * {@link #writeRemoteObject}. The written data contains discriminator, + * defining, that was written. Another method that writes the same content is + * {@link org.omg.CORBA_2_3.portable.OutputStream#write_abstract_interface(java.lang.Object)}. + * + * @param output a stream to write to, must be + * {@link org.omg.CORBA_2_3.portable.OutputStream}. + * + * @param object an object to write, must be CORBA object, Remote + */ + public void writeAbstractObject(OutputStream output, Object object) + { + ((org.omg.CORBA_2_3.portable.OutputStream) output).write_abstract_interface(object); + } + + /** + * Write the passed java object to the output stream in the form of the CORBA + * {@link Any}. This includes creating an writing the object {@link TypeCode} + * first. Such Any can be later read by a non-RMI-IIOP CORBA implementation + * and manipulated, for instance, by means, provided in + * {@link org.omg.DynamicAny.DynAny}. Depending from the passed value, this + * method writes CORBA object, value type or value box. For value types Null + * is written with the abstract interface, its typecode having repository id + * "IDL:omg.org/CORBA/AbstractBase:1.0" and the empty string name. + * + * @param output the object to write. + * @param object the java object that must be written in the form of the CORBA + * {@link Any}. + */ + public void writeAny(OutputStream output, Object object) + { + Any any = output.orb().create_any(); + if (object == null) + { + GeneralTypeCode t = new GeneralTypeCode(TCKind.tk_abstract_interface); + t.setId("IDL:omg.org/CORBA/AbstractBase:1.0"); + t.setName(""); + any.type(t); + output.write_any(any); + return; + } + else if (object instanceof org.omg.CORBA.Object + && !(object instanceof Remote)) + { + // Write as value type. + boolean inserted = ObjectCreator.insertWithHelper(any, object); + if (inserted) + { + output.write_any(any); + return; + } + } + + if (object instanceof org.omg.CORBA.Object) + writeAnyAsRemote(output, object); + else if (object instanceof Serializable) + { + any.insert_Value((Serializable) object); + output.write_any(any); + } + else + { + MARSHAL m = new MARSHAL(object.getClass().getName() + + " must be CORBA Object, Remote or Serializable"); + m.minor = Minor.NonSerializable; + throw m; + } + } + + /** + * Write Any as for remote object. + */ + void writeAnyAsRemote(OutputStream output, Object object) + { + GeneralTypeCode t = new GeneralTypeCode(TCKind.tk_objref); + t.setId(m_ValueHandler.getRMIRepositoryID(object.getClass())); + t.setName(object.getClass().getName()); + + // Writing Any (typecode, followed by value). + output.write_TypeCode(t); + writeRemoteObject(output, object); + } + + /** + * Get the class name excluding the package name. + */ + String getName(String n) + { + int p = n.lastIndexOf('.'); + if (p < 0) + return n; + else + return n.substring(p + 1); + } + + /** + * Read Any from the input stream. + */ + public Object readAny(InputStream input) + { + return input.read_any(); + } + + /** + * Write the passed parameter to the output stream as CORBA object. If the + * parameter is an instance of Remote and not an instance of Stub, the method + * instantiates a suitable Tie, connects the parameter to this Tie and then + * connects that Tie to the ORB that is requested from the output stream. Then + * the object reference is written to the stream, making remote invocations + * possible. This method is used in write_value(..) method group in + * {@link org.omg.CORBA_2_3.portable.OutputStream} and also may be called + * directly from generated Stubs and Ties. + * + * @param output a stream to write to, must be + * org.omg.CORBA_2_3.portable.OutputStream + * @param object an object to write. + */ + public void writeRemoteObject(OutputStream an_output, Object object) + { + org.omg.CORBA_2_3.portable.OutputStream output = (org.omg.CORBA_2_3.portable.OutputStream) an_output; + if (object == null) + an_output.write_Object(null); + else if (isTieRequired(object)) + { + // Find the interface that is implemented by the object and extends + // Remote. + Class fc = getExportedInterface(object); + exportTie(output, object, fc); + } + else if (object instanceof org.omg.CORBA.Object) + { + ensureOrbRunning(output); + an_output.write_Object((org.omg.CORBA.Object) object); + } + else if (object != null && object instanceof Serializable) + writeFields(an_output, (Serializable) object); + } + +} diff --git a/libjava/classpath/gnu/javax/rmi/CORBA/ValueHandlerDelegateImpl.java b/libjava/classpath/gnu/javax/rmi/CORBA/ValueHandlerDelegateImpl.java new file mode 100644 index 000000000..33fff16e5 --- /dev/null +++ b/libjava/classpath/gnu/javax/rmi/CORBA/ValueHandlerDelegateImpl.java @@ -0,0 +1,163 @@ +/* ValueHandlerDelegateImpl.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.rmi.CORBA; + +import gnu.CORBA.CDR.gnuRuntime; + +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.CustomMarshal; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.Streamable; +import org.omg.SendingContext.RunTime; + +import java.io.Externalizable; +import java.io.ObjectStreamClass; +import java.io.Serializable; +import java.rmi.Remote; + +import javax.rmi.CORBA.ValueHandler; +import javax.rmi.CORBA.ValueHandlerMultiFormat; + +/** + * Implementation of the ValueHandler. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) (implementation) + */ +public class ValueHandlerDelegateImpl + extends RmiUtilities + implements ValueHandler, ValueHandlerMultiFormat +{ + /** + * Return the maximal supported stream format version. We currently + * support the version 1. + * + * TODO Support the version 2. + */ + public byte getMaximumStreamFormatVersion() + { + return 1; + } + + /** + * Write value using the given stream format version. + */ + public void writeValue(OutputStream output, Serializable value, byte version) + { + if (version!=1) + throw new BAD_PARAM("Unsupported stream format version "+version); + else + writeValue(output, value); + } + + /** + * This implementation associates RunTime with stream rather than with the + * value handler and this method is not used in the implementation. It is + * implemented just for the sake of compatibility. + */ + public RunTime getRunTimeCodeBase() + { + return new gnuRuntime(null, null); + } + + /** + * Checks if an instance of this class can write its fields itself. + */ + public boolean isCustomMarshaled(Class clz) + { + return CustomMarshal.class.isAssignableFrom(clz) + || Streamable.class.isAssignableFrom(clz); + } + + /** + * No replacement, returns the passed parameter. + */ + public Serializable writeReplace(Serializable value) + { + return value; + } + + /** + * Compute the repository id in the RMI hashed format. + */ + public String getRMIRepositoryID(final Class cx) + { + long hash = 0; + Class of = cx.isArray() ? cx.getComponentType() : null; + + if (cx.equals(String[].class)) + return RMI_STRING_ARRAY_ID; + else if (cx.equals(String.class)) + return RMI_STRING_ID; + else if (cx.equals(Class.class)) + return RMI_CLASS_ID; + else if (Remote.class.isAssignableFrom(cx) + || !Serializable.class.isAssignableFrom(cx) + || cx.isInterface() + || (cx.isArray() && (!Serializable.class.isAssignableFrom(of) + || of.isPrimitive() || Remote.class.isAssignableFrom(of))) + + ) + // Some classes that have zero hash code and serial no version id + // included. + return "RMI:" + cx.getName() + ":" + toHex(hash); + else if (cx.isArray()) + // Arrays have the same hashcode and uid as they components. + return "RMI:" + cx.getName() + ":" + toHex(getHashCode(of)) + ":" + + toHex(getSid(of)); + else + { + if (Externalizable.class.isAssignableFrom(cx)) + hash = 1; + else + hash = getHashCode(cx); + + return "RMI:" + cx.getName() + ":" + toHex(hash) + ":" + + toHex(getSid(cx)); + } + } + + /** + * Get the class serial version UID. + */ + long getSid(Class cx) + { + ObjectStreamClass osc = ObjectStreamClass.lookup(cx); + return osc.getSerialVersionUID(); + } +} diff --git a/libjava/classpath/gnu/javax/security/auth/Password.java b/libjava/classpath/gnu/javax/security/auth/Password.java new file mode 100644 index 000000000..8fb07ee6b --- /dev/null +++ b/libjava/classpath/gnu/javax/security/auth/Password.java @@ -0,0 +1,283 @@ +/* Password.java -- opaque wrapper around a password. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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; + +import gnu.java.security.util.ExpirableObject; + +/** + * Immutible, though destroyable, password class. + * + *

    Extends {@link ExpirableObject}, implementing {@link doDestroy()} + * in which encapsulated {@link char[]}, and {@link byte[]} password fields + * are cleared (elements set to zero) in order to thwart memory heap + * snooping. + */ +public final class Password extends ExpirableObject +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** + * Password stored in {@link char[]} format. + */ + private final char[] password; + + /** + * Password stored in {@link byte[]} format. + */ + private final byte[] bPassword; + + /** + * Indicates whether this Password object's {@link doDestroy()} method has + * been called. See also, {@link ExpirableObject#Destroy()}. + */ + private boolean mIsDestroyed = false; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Create a new expirable Password object that will expire after the + * default timeout {@link ExpirableObject#DEFAULT_TIMEOUT}. + * + * @param password The character array password to associate with this + * Password object. + */ + public Password (char[] password) + { + this (password, 0, password.length, DEFAULT_TIMEOUT); + } + + /** + * Create a new expirable Password object that will expire after the + * timeout denoted by constructor parameter, delay. + * + * @param password The character array password to associate with this + * Password object. + * @param delay The number of miliseconds before this Password object + * will be automatically destroyed. + */ + public Password (char[] password, long delay) + { + this (password, 0, password.length, delay); + } + + /** + * Create a new expirable Password object that will expire after the + * default timeout {@link ExpirableObject#DEFAULT_TIMEOUT}. + * + * @param password The character array password to associate with this + * Password object. + * @param offset The password character array parameter element + * marking the beginning of the contained password string. + * @param length The number of characters, beginning at offset, + * to be copied into this object's {@link password} field. + */ + public Password (char[] password, int offset, int length) + { + this (password, offset, length, DEFAULT_TIMEOUT); + } + + /** + * Create a new expirable Password object that will expire after the + * timeout denoted by constructor parameter, delay. + * + * @param password The character array password to associate with this + * Password object. + * @param offset The password character array parameter element + * marking the beginning of the contained password string. + * @param length The number of characters, beginning at offset, + * to be copied into this object's {@link password} field. + * @param delay The number of miliseconds before this Password object + * will be automatically destroyed. + */ + public Password (char[] password, int offset, int length, long delay) + { + super (delay); + + if (offset < 0 || length < 0 || offset + length > password.length) + throw new ArrayIndexOutOfBoundsException ("off=" + offset + " length=" + + length + " array.length=" + + password.length); + + int i, j; + this.password = new char[length]; + bPassword = new byte[length]; + + for(i = 0, j = offset; i < length; i++, j++) + { + this.password[i] = password[j]; + // XXX this should use character encodings, other than ASCII. + bPassword[i] = (byte) (password[j] & 0x7F); + } + } + + /** + * Create a new expirable Password object that will expire after the + * default timeout {@link ExpirableObject#DEFAULT_TIMEOUT}. + * + * @param password The byte array password to associate with this + * Password object. + */ + public Password (byte[] password) + { + this (password, 0, password.length, DEFAULT_TIMEOUT); + } + + /** + * Create a new expirable Password object that will expire after the + * timeout denoted by constructor parameter, delay. + * + * @param password The byte array password to associate with this + * Password object. + * @param delay The number of miliseconds before this Password object + * will be automatically destroyed. + */ + public Password (byte[] password, long delay) + { + this (password, 0, password.length, delay); + } + + /** + * Create a new expirable Password object that will expire after the + * default timeout {@link ExpirableObject#DEFAULT_TIMEOUT}. + * + * @param password The byte array password to associate with this + * Password object. + * @param offset The password byte array parameter element + * marking the beginning of the contained password string. + * @param length The number of bytes, beginning at offset, + * to be copied into this object's {@link password} field. + */ + public Password (byte[] password, int offset, int length) + { + this (password, offset, length, DEFAULT_TIMEOUT); + } + + /** + * Create a new expirable Password object that will expire after the + * timeout denoted by constructor parameter, delay. + * + * @param password The byte array password to associate with this + * Password object. + * @param offset The password byte array parameter element + * marking the beginning of the contained password string. + * @param length The number of bytes, beginning at offset, + * to be copied into this object's {@link bPassword} field. + * @param delay The number of miliseconds before this Password object + * will be automatically destroyed. + */ + public Password (byte[] password, int offset, int length, long delay) + { + super (delay); + + if (offset < 0 || length < 0 || offset + length > password.length) + throw new ArrayIndexOutOfBoundsException ("off=" + offset + " length=" + + length + " array.length=" + + password.length); + + int i, j; + this.password = new char[length]; + bPassword = new byte[length]; + + for (i = 0, j = offset; i < length; i++, j++) + { + this.password[i] = (char) password[j]; + bPassword[i] = password[j]; + } + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + * Returns a reference to the {@link char[]} password storage field, + * {@link password}. + */ + public synchronized char[] getPassword() + { + if (mIsDestroyed) + throw new IllegalStateException ("Attempted destroyed password access."); + + return password; + } + + /** + * Returns a reference to the {@link byte[]} password storage field, + * {@link bPassword}. + */ + public synchronized byte[] getBytes() + { + if (mIsDestroyed) + throw new IllegalStateException ("Attempted destroyed password access."); + + return bPassword; + } + + /** + * Sets password field char[], and byte[] array elements to zero. + * This method implements base class {@link ExpirableObject} abstract + * method, {@link ExpirableObject#doDestroy()}. See also, + * {@link ExpirableObject#destroy()}. + */ + protected synchronized void doDestroy() + { + if (isDestroyed()) + return; + else + { + for (int i = 0; i < password.length; i++) + password[i] = 0; + for (int i = 0; i < bPassword.length; i++) + bPassword[i] = 0; + mIsDestroyed = true; + } + } + + /** + * Returns true, or false relative to whether, or not this object's + * {@link doDestroy()} method has been called. See also, + * {@ExpirableObject#destroy()}. + */ + public synchronized boolean isDestroyed() + { + return (mIsDestroyed); + } +} diff --git a/libjava/classpath/gnu/javax/security/auth/callback/AWTCallbackHandler.java b/libjava/classpath/gnu/javax/security/auth/callback/AWTCallbackHandler.java new file mode 100644 index 000000000..f241157ee --- /dev/null +++ b/libjava/classpath/gnu/javax/security/auth/callback/AWTCallbackHandler.java @@ -0,0 +1,454 @@ +/* AWTCallbackHandler.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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 gnu.java.lang.CPStringBuilder; + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Dialog; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Label; +import java.awt.List; +import java.awt.Panel; +import java.awt.TextArea; +import java.awt.TextField; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; + +import java.util.Locale; + +import javax.security.auth.callback.ChoiceCallback; +import javax.security.auth.callback.ConfirmationCallback; +import javax.security.auth.callback.LanguageCallback; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.TextInputCallback; +import javax.security.auth.callback.TextOutputCallback; + +public class AWTCallbackHandler extends AbstractCallbackHandler + implements ActionListener, WindowListener +{ + + // Fields. + // ------------------------------------------------------------------------- + + protected String actionCommand; + + private static final String ACTION_CANCEL = "CANCEL"; + private static final String ACTION_NO = "NO"; + private static final String ACTION_NONE = "NONE"; + private static final String ACTION_OK = "OK"; + private static final String ACTION_YES = "YES"; + + // Constructor. + // ------------------------------------------------------------------------- + + public AWTCallbackHandler() + { + super ("AWT"); + actionCommand = ACTION_NONE; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + protected synchronized void handleChoice(ChoiceCallback c) + { + Frame ownerFrame = new Frame(); + Dialog dialog = new Dialog(ownerFrame); + String[] choices = c.getChoices(); + dialog.setTitle(c.getPrompt()); + Label label = new Label(c.getPrompt()); + List list = new List(Math.min(5, choices.length), + c.allowMultipleSelections()); + Panel buttons = new Panel(); + Button ok = new Button(messages.getString("callback.ok")); + ok.setActionCommand(ACTION_OK); + ok.addActionListener(this); + Button cancel = new Button(messages.getString("callback.cancel")); + cancel.setActionCommand(ACTION_CANCEL); + cancel.addActionListener(this); + for (int i = 0; i < choices.length; i++) + { + list.add(choices[i]); + } + if (c.getDefaultChoice() >= 0 && c.getDefaultChoice() < choices.length) + { + list.select(c.getDefaultChoice()); + } + dialog.setLayout(new BorderLayout()); + dialog.add(label, BorderLayout.NORTH); + dialog.add(list, BorderLayout.CENTER); + buttons.setLayout(new FlowLayout(FlowLayout.RIGHT)); + buttons.add(cancel); + buttons.add(ok); + dialog.add(buttons, BorderLayout.SOUTH); + dialog.pack(); + dialog.show(); + try { wait(); } + catch (InterruptedException ie) { } + if (actionCommand.equals(ACTION_OK)) + { + if (c.allowMultipleSelections()) + { + c.setSelectedIndexes(list.getSelectedIndexes()); + } + else + { + c.setSelectedIndex(list.getSelectedIndex()); + } + } + dialog.dispose(); + ownerFrame.dispose(); + } + + protected synchronized void handleConfirmation(ConfirmationCallback c) + { + Frame ownerFrame = new Frame(); + Dialog dialog = new Dialog(ownerFrame); + switch (c.getMessageType()) + { + case ConfirmationCallback.ERROR: + dialog.setTitle(messages.getString("callback.error")); + break; + case ConfirmationCallback.INFORMATION: + dialog.setTitle(messages.getString("callback.information")); + break; + case ConfirmationCallback.WARNING: + dialog.setTitle(messages.getString("callback.warning")); + break; + default: + dialog.setTitle(""); + } + dialog.setLayout(new GridLayout(2, 1)); + dialog.add(new Label(c.getPrompt())); + Panel buttons = new Panel(); + buttons.setLayout(new FlowLayout(FlowLayout.RIGHT)); + dialog.add(buttons); + String[] choices = null; + int[] values = null; + switch (c.getOptionType()) + { + case ConfirmationCallback.OK_CANCEL_OPTION: + choices = new String[] { + messages.getString("callback.cancel"), + messages.getString("callback.ok") + }; + values = new int[] { + ConfirmationCallback.CANCEL, ConfirmationCallback.OK + }; + break; + case ConfirmationCallback.YES_NO_CANCEL_OPTION: + choices = new String[] { + messages.getString("callback.cancel"), + messages.getString("callback.no"), + messages.getString("callback.yes") + }; + values = new int[] { + ConfirmationCallback.CANCEL, ConfirmationCallback.NO, + ConfirmationCallback.YES + }; + break; + case ConfirmationCallback.YES_NO_OPTION: + choices = new String[] { + messages.getString("callback.no"), + messages.getString("callback.yes") + }; + values = new int[] { + ConfirmationCallback.NO, ConfirmationCallback.YES + }; + break; + case ConfirmationCallback.UNSPECIFIED_OPTION: + choices = c.getOptions(); + values = new int[choices.length]; + for (int i = 0; i < values.length; i++) + values[i] = i; + break; + default: + throw new IllegalArgumentException(); + } + for (int i = 0; i < choices.length; i++) + { + Button b = new Button(choices[i]); + b.setActionCommand(choices[i]); + b.addActionListener(this); + buttons.add(b); + } + dialog.pack(); + dialog.show(); + try { wait(); } + catch (InterruptedException ie) { } + for (int i = 0; i < choices.length; i++) + { + if (actionCommand.equals(choices[i])) + { + c.setSelectedIndex(values[i]); + break; + } + } + dialog.dispose(); + ownerFrame.dispose(); + } + + protected synchronized void handleLanguage(LanguageCallback c) + { + Locale[] locales = Locale.getAvailableLocales(); + String[] languages = new String[locales.length]; + Locale def = Locale.getDefault(); + int defind = 0; + for (int i = 0; i < locales.length; i++) + { + CPStringBuilder lang = + new CPStringBuilder(locales[i].getDisplayLanguage(locales[i])); + String country = locales[i].getDisplayCountry(locales[i]); + String variant = locales[i].getDisplayVariant(locales[i]); + if (country.length() > 0 && variant.length() > 0) + { + lang.append(" ("); + lang.append(country); + lang.append(", "); + lang.append(variant); + lang.append(")"); + } + else if (country.length() > 0) + { + lang.append(" ("); + lang.append(country); + lang.append(")"); + } + else if (variant.length() > 0) + { + lang.append(" ("); + lang.append(variant); + lang.append(")"); + } + languages[i] = lang.toString(); + if (locales[i].equals(def)) + defind = i; + } + ChoiceCallback c2 = + new ChoiceCallback(messages.getString("callback.language"), languages, + defind, false); + handleChoice(c2); + c.setLocale(def); + if (c2.getSelectedIndexes() != null && c2.getSelectedIndexes().length > 0) + { + int index = c2.getSelectedIndexes()[0]; + if (index >= 0 && index < locales.length) + c.setLocale(locales[index]); + } + } + + protected synchronized void handleName(NameCallback c) + { + Frame ownerFrame = new Frame(); + Dialog dialog = new Dialog(ownerFrame); + dialog.setTitle(c.getPrompt()); + dialog.setLayout(new GridLayout(3, 1)); + Label label = new Label(c.getPrompt()); + TextField input = new TextField(); + if (c.getDefaultName() != null) + { + input.setText(c.getDefaultName()); + } + Panel buttons = new Panel(); + Button ok = new Button(messages.getString("callback.ok")); + ok.setActionCommand(ACTION_OK); + ok.addActionListener(this); + Button cancel = new Button(messages.getString("callback.cancel")); + cancel.setActionCommand(ACTION_CANCEL); + cancel.addActionListener(this); + dialog.add(label); + dialog.add(input); + buttons.setLayout(new FlowLayout(FlowLayout.RIGHT)); + buttons.add(ok); + buttons.add(cancel); + dialog.add(buttons); + dialog.pack(); + dialog.show(); + try { wait(); } + catch (InterruptedException ie) { } + if (actionCommand.equals(ACTION_OK)) + { + c.setName(input.getText()); + } + dialog.dispose(); + ownerFrame.dispose(); + } + + protected synchronized void handlePassword(PasswordCallback c) + { + Frame ownerFrame = new Frame(); + Dialog dialog = new Dialog(ownerFrame); + dialog.setTitle(c.getPrompt()); + dialog.setLayout(new GridLayout(3, 1)); + Label label = new Label(c.getPrompt()); + TextField input = new TextField(); + if (!c.isEchoOn()) + { + input.setEchoChar('*'); + } + Panel buttons = new Panel(); + Button ok = new Button(messages.getString("callback.ok")); + ok.setActionCommand(ACTION_OK); + ok.addActionListener(this); + Button cancel = new Button(messages.getString("callback.cancel")); + cancel.setActionCommand(ACTION_CANCEL); + cancel.addActionListener(this); + dialog.add(label); + dialog.add(input); + buttons.setLayout(new FlowLayout(FlowLayout.RIGHT)); + buttons.add(ok); + buttons.add(cancel); + dialog.add(buttons); + dialog.pack(); + dialog.show(); + try { wait(); } + catch (InterruptedException ie) { } + if (actionCommand.equals(ACTION_OK)) + { + c.setPassword(input.getText().toCharArray()); + } + dialog.dispose(); + ownerFrame.dispose(); + } + + protected synchronized void handleTextInput(TextInputCallback c) + { + Frame ownerFrame = new Frame(); + Dialog dialog = new Dialog(ownerFrame); + dialog.setTitle(c.getPrompt()); + dialog.setLayout(new BorderLayout()); + Label label = new Label(c.getPrompt()); + TextArea text = new TextArea(10, 40); + if (c.getDefaultText() != null) + { + text.setText(c.getDefaultText()); + } + Panel buttons = new Panel(); + Button ok = new Button(messages.getString("callback.ok")); + ok.setActionCommand(ACTION_OK); + ok.addActionListener(this); + Button cancel = new Button(messages.getString("callback.cancel")); + cancel.setActionCommand(ACTION_CANCEL); + cancel.addActionListener(this); + dialog.add(label, BorderLayout.NORTH); + dialog.add(text, BorderLayout.CENTER); + buttons.setLayout(new FlowLayout(FlowLayout.RIGHT)); + buttons.add(ok); + buttons.add(cancel); + dialog.add(buttons, BorderLayout.SOUTH); + dialog.pack(); + dialog.show(); + try { wait(); } + catch (InterruptedException ie) { } + if (actionCommand.equals(ACTION_OK)) + { + c.setText(text.getText()); + } + dialog.dispose(); + ownerFrame.dispose(); + } + + protected synchronized void handleTextOutput(TextOutputCallback c) + { + Frame ownerFrame = new Frame(); + Dialog dialog = new Dialog(ownerFrame); + dialog.setLayout(new GridLayout(2, 1)); + switch (c.getMessageType() /*c.getStyle()*/) + { + case ConfirmationCallback.ERROR: + dialog.setTitle(messages.getString("callback.error")); + break; + case ConfirmationCallback.INFORMATION: + dialog.setTitle(messages.getString("callback.information")); + break; + case ConfirmationCallback.WARNING: + dialog.setTitle(messages.getString("callback.warning")); + break; + default: + dialog.setTitle(""); + } + Label label = new Label(c.getMessage()); + Panel buttons = new Panel(); + Button ok = new Button(messages.getString("callback.ok")); + buttons.setLayout(new FlowLayout(FlowLayout.RIGHT)); + buttons.add(ok); + ok.addActionListener(this); + dialog.add(label); + dialog.add(buttons); + dialog.pack(); + dialog.show(); + try { wait(); } + catch (InterruptedException ie) { } + dialog.dispose(); + ownerFrame.dispose(); + } + + // ActionListener interface implementation. + // ------------------------------------------------------------------------- + + public synchronized void actionPerformed(ActionEvent ae) + { + actionCommand = ae.getActionCommand(); + notifyAll(); + } + + // WindowListener interface implementation. + // ------------------------------------------------------------------------- + + public synchronized void windowClosing(WindowEvent we) + { + actionCommand = ACTION_NONE; + notifyAll(); + } + + public void windowOpened(WindowEvent we) { } + public void windowClosed(WindowEvent we) { } + public void windowIconified(WindowEvent we) { } + public void windowDeiconified(WindowEvent we) { } + public void windowActivated(WindowEvent we) { } + public void windowDeactivated(WindowEvent we) { } +} diff --git a/libjava/classpath/gnu/javax/security/auth/callback/AbstractCallbackHandler.java b/libjava/classpath/gnu/javax/security/auth/callback/AbstractCallbackHandler.java new file mode 100644 index 000000000..31a7f5aca --- /dev/null +++ b/libjava/classpath/gnu/javax/security/auth/callback/AbstractCallbackHandler.java @@ -0,0 +1,295 @@ +/* AbstractCallbackHandler.java -- + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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 gnu.java.security.Engine; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.util.PropertyResourceBundle; +import java.util.ResourceBundle; + +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.Security; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.ChoiceCallback; +import javax.security.auth.callback.ConfirmationCallback; +import javax.security.auth.callback.LanguageCallback; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.TextInputCallback; +import javax.security.auth.callback.TextOutputCallback; +import javax.security.auth.callback.UnsupportedCallbackException; + +public abstract class AbstractCallbackHandler implements CallbackHandler +{ + + // Fields. + // ------------------------------------------------------------------------- + + private static final String SERVICE = "CallbackHandler"; + + protected final ResourceBundle messages; + + private final String name; + + // Constructors. + // ------------------------------------------------------------------------- + + protected AbstractCallbackHandler (final String name) + { + super(); + messages = PropertyResourceBundle.getBundle("gnu/javax/security/auth/callback/MessagesBundle"); + this.name = name; + } + + /** + * Create an instance of CallbackHandler of the designated + * type from the first Security Provider which offers it. + * + * @param type the type of callback handler to create. + * @return a newly created instance of ClassbackHandler. + * @throws NoSuchAlgorithmException if no security provider is found to offer + * an implementation of CallbackHandler of the + * designated type. + */ + public static CallbackHandler getInstance(String type) + throws NoSuchAlgorithmException + { + Provider[] p = Security.getProviders(); + NoSuchAlgorithmException lastException = null; + for (int i = 0; i < p.length; i++) + try + { + return getInstance(type, p[i]); + } + catch (NoSuchAlgorithmException x) + { + lastException = x; + } + if (lastException != null) + throw lastException; + throw new NoSuchAlgorithmException(type); + } + + /** + * Create an instance of CallbackHandler of the designated + * type from the named security provider. + * + * @param type the type of callback handler to create. + * @param provider a named security provider to use. + * @return a newly created instance of ClassbackHandler. + * @throws NoSuchAlgorithmException if no security provider is found to offer + * an implementation of CallbackHandler of the + * designated type. + * @throws IllegalArgumentException if either type or + * provider is null, or if + * type is an empty string. + */ + public static CallbackHandler getInstance(String type, String provider) + throws NoSuchAlgorithmException, NoSuchProviderException + { + if (provider == null) + throw new IllegalArgumentException("provider MUST NOT be null"); + Provider p = Security.getProvider(provider); + if (p == null) + throw new NoSuchProviderException(provider); + return getInstance(type, p); + } + + /** + * Create an instance of CallbackHandler of the designated + * type from the designated security provider. + * + * @param type the type of callback handler to create. + * @param provider a security provider to use. + * @return a newly created instance of ClassbackHandler. + * @throws NoSuchAlgorithmException if no security provider is found to offer + * an implementation of CallbackHandler of the + * designated type. + * @throws IllegalArgumentException if either type or + * provider is null, or if + * type is an empty string. + */ + public static CallbackHandler getInstance(String type, Provider provider) + throws NoSuchAlgorithmException + { + StringBuilder sb = new StringBuilder("CallbackHandler of type [") + .append(type).append("] from provider[") + .append(provider).append("] could not be created"); + Throwable cause; + try + { + return (CallbackHandler) Engine.getInstance(SERVICE, type, provider); + } + catch (InvocationTargetException x) + { + cause = x.getCause(); + if (cause instanceof NoSuchAlgorithmException) + throw (NoSuchAlgorithmException) cause; + if (cause == null) + cause = x; + } + catch (ClassCastException x) + { + cause = x; + } + NoSuchAlgorithmException x = new NoSuchAlgorithmException(sb.toString()); + x.initCause(cause); + throw x; + } + + public void handle(Callback[] callbacks) + throws IOException, UnsupportedCallbackException + { + if (callbacks == null) + throw new NullPointerException(); + for (int i = 0; i < callbacks.length; i++) + { + if (callbacks[i] == null) + continue; + if (callbacks[i] instanceof ChoiceCallback) + handleChoice((ChoiceCallback) callbacks[i]); + else if (callbacks[i] instanceof ConfirmationCallback) + handleConfirmation((ConfirmationCallback) callbacks[i]); + else if (callbacks[i] instanceof LanguageCallback) + handleLanguage((LanguageCallback) callbacks[i]); + else if (callbacks[i] instanceof NameCallback) + handleName((NameCallback) callbacks[i]); + else if (callbacks[i] instanceof PasswordCallback) + handlePassword((PasswordCallback) callbacks[i]); + else if (callbacks[i] instanceof TextInputCallback) + handleTextInput((TextInputCallback) callbacks[i]); + else if (callbacks[i] instanceof TextOutputCallback) + handleTextOutput((TextOutputCallback) callbacks[i]); + else + handleOther(callbacks[i]); + } + } + + public final String getName () + { + return name; + } + + // Abstract methods. + // ------------------------------------------------------------------------- + + /** + * Handles a {@link ChoiceCallback}. + * + * @param callback The choice callback. + * @throws IOException If an I/O error occurs. + */ + protected abstract void handleChoice(ChoiceCallback callback) + throws IOException; + + /** + * Handles a {@link ConfirmationCallback}. + * + * @param callback The confirmation callback. + * @throws IOException If an I/O error occurs. + */ + protected abstract void handleConfirmation(ConfirmationCallback callback) + throws IOException; + + /** + * Handles a {@link LanguageCallback}. + * + * @param callback The language callback. + * @throws IOException If an I/O error occurs. + */ + protected abstract void handleLanguage(LanguageCallback callback) + throws IOException; + + /** + * Handles a {@link NameCallback}. + * + * @param callback The name callback. + * @throws IOException If an I/O error occurs. + */ + protected abstract void handleName(NameCallback callback) + throws IOException; + + /** + * Handles a {@link PasswordCallback}. + * + * @param callback The password callback. + * @throws IOException If an I/O error occurs. + */ + protected abstract void handlePassword(PasswordCallback callback) + throws IOException; + + /** + * Handles a {@link TextInputCallback}. + * + * @param callback The text input callback. + * @throws IOException If an I/O error occurs. + */ + protected abstract void handleTextInput(TextInputCallback callback) + throws IOException; + + /** + * Handles a {@link TextOutputCallback}. + * + * @param callback The text output callback. + * @throws IOException If an I/O error occurs. + */ + protected abstract void handleTextOutput(TextOutputCallback callback) + throws IOException; + + /** + * Handles an unknown callback. The default implementation simply throws + * an {@link UnsupportedCallbackException}. + * + * @param callback The callback to handle. + * @throws IOException If an I/O error occurs. + * @throws UnsupportedCallbackException If the specified callback is not + * supported. + */ + protected void handleOther(Callback callback) + throws IOException, UnsupportedCallbackException + { + throw new UnsupportedCallbackException(callback); + } +} diff --git a/libjava/classpath/gnu/javax/security/auth/callback/CertificateCallback.java b/libjava/classpath/gnu/javax/security/auth/callback/CertificateCallback.java new file mode 100644 index 000000000..74885ed21 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/security/auth/callback/ConsoleCallbackHandler.java b/libjava/classpath/gnu/javax/security/auth/callback/ConsoleCallbackHandler.java new file mode 100644 index 000000000..4c24ab808 --- /dev/null +++ b/libjava/classpath/gnu/javax/security/auth/callback/ConsoleCallbackHandler.java @@ -0,0 +1,299 @@ +/* ConsoleCallbackHandler.java -- + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.PrintStream; + +import java.util.Iterator; +import java.util.Locale; +import java.util.StringTokenizer; +import java.util.TreeSet; + +import javax.security.auth.callback.ChoiceCallback; +import javax.security.auth.callback.ConfirmationCallback; +import javax.security.auth.callback.LanguageCallback; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.TextInputCallback; +import javax.security.auth.callback.TextOutputCallback; + +/** + * An implementation of {@link CallbackHandler} that reads and writes + * information to and from System.in and System.out. + */ +public class ConsoleCallbackHandler extends AbstractCallbackHandler +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final PrintStream out; + + // Constructors. + // ------------------------------------------------------------------------- + + public ConsoleCallbackHandler() + { + this (System.out); + } + + public ConsoleCallbackHandler (final PrintStream out) + { + super ("CONSOLE"); + this.out = out; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + protected void handleChoice(ChoiceCallback c) throws IOException + { + BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); + out.println(c.getPrompt()); + out.print('('); + String[] choices = c.getChoices(); + for (int i = 0; i < choices.length; i++) + { + out.print(choices[i]); + if (i != choices.length - 1) + out.print(", "); + } + out.print(") "); + if (c.getDefaultChoice() >= 0 && c.getDefaultChoice() < choices.length) + { + out.print('['); + out.print(choices[c.getDefaultChoice()]); + out.print("] "); + } + String reply = in.readLine(); + if (reply == null || reply.length() == 0) + { + c.setSelectedIndex(c.getDefaultChoice()); + return; + } + if (!c.allowMultipleSelections()) + { + for (int i = 0; i < choices.length; i++) + { + if (reply.trim().equals(choices[i])) + { + c.setSelectedIndex(i); + return; + } + } + c.setSelectedIndex(c.getDefaultChoice()); + } + else + { + TreeSet indices = new TreeSet(); + StringTokenizer tok = new StringTokenizer(reply, ","); + String[] replies = new String[tok.countTokens()]; + int idx = 0; + while (tok.hasMoreTokens()) + { + replies[idx++] = tok.nextToken().trim(); + } + for (int i = 0; i < choices.length; i++) + for (int j = 0; j < replies.length; i++) + { + if (choices[i].equals(replies[j])) + { + indices.add(Integer.valueOf(i)); + } + } + if (indices.size() == 0) + c.setSelectedIndex(c.getDefaultChoice()); + else + { + int[] ii = new int[indices.size()]; + int i = 0; + for (Iterator it = indices.iterator(); it.hasNext(); ) + ii[i++] = ((Integer) it.next()).intValue(); + c.setSelectedIndexes(ii); + } + } + } + + protected void handleConfirmation(ConfirmationCallback c) throws IOException + { + BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); + if (c.getPrompt() != null) + out.print(c.getPrompt()); + + String[] choices = null; + int[] values = null; + switch (c.getOptionType()) + { + case ConfirmationCallback.OK_CANCEL_OPTION: + out.print(messages.getString("callback.okCancel")); + choices = new String[] { + messages.getString("callback.ok"), + messages.getString("callback.cancel"), + messages.getString("callback.shortOk"), + messages.getString("callback.shortCancel") + }; + values = new int[] { + ConfirmationCallback.OK, ConfirmationCallback.CANCEL, + ConfirmationCallback.OK, ConfirmationCallback.CANCEL + }; + break; + + case ConfirmationCallback.YES_NO_CANCEL_OPTION: + out.print(messages.getString("callback.yesNoCancel")); + choices = new String[] { + messages.getString("callback.yes"), + messages.getString("callback.no"), + messages.getString("callback.cancel"), + messages.getString("callback.shortYes"), + messages.getString("callback.shortNo"), + messages.getString("callback.shortCancel") + }; + values = new int[] { + ConfirmationCallback.YES, ConfirmationCallback.NO, + ConfirmationCallback.CANCEL, ConfirmationCallback.YES, + ConfirmationCallback.NO, ConfirmationCallback.CANCEL + }; + break; + + case ConfirmationCallback.YES_NO_OPTION: + out.print(messages.getString("callback.yesNo")); + choices = new String[] { messages.getString("callback.yes"), + messages.getString("callback.no"), + messages.getString("callback.shortYes"), + messages.getString("callback.shortNo") }; + values = new int[] { ConfirmationCallback.YES, + ConfirmationCallback.NO, + ConfirmationCallback.YES, + ConfirmationCallback.NO }; + int defaultOption = c.getDefaultOption(); + if (defaultOption > -1 && defaultOption < choices.length) + { + out.print("["); + out.print(choices[defaultOption]); + out.print("] "); + } + break; + + case ConfirmationCallback.UNSPECIFIED_OPTION: + choices = c.getOptions(); + values = new int[choices.length]; + for (int i = 0; i < values.length; i++) + values[i] = i; + out.print('('); + for (int i = 0; i < choices.length; i++) + { + out.print(choices[i]); + if (i != choices.length - 1) + out.print(", "); + } + out.print(") ["); + out.print(choices[c.getDefaultOption()]); + out.print("] "); + break; + + default: + throw new IllegalArgumentException(); + } + String reply = in.readLine(); + if (reply == null) + { + c.setSelectedIndex(c.getDefaultOption()); + return; + } + reply = reply.trim(); + for (int i = 0; i < choices.length; i++) + if (reply.equalsIgnoreCase(choices[i])) + { + c.setSelectedIndex(values[i]); + return; + } + c.setSelectedIndex(c.getDefaultOption()); + } + + protected void handleLanguage(LanguageCallback c) throws IOException + { + BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); + out.print(messages.getString("callback.language")); + String reply = null; + reply = in.readLine(); + if (reply == null) + { + c.setLocale(Locale.getDefault()); + } + else + { + c.setLocale(new Locale(reply.trim())); + } + } + + protected void handleName(NameCallback c) throws IOException + { + BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); + out.print(c.getPrompt()); + String name = in.readLine(); + if (name != null) + c.setName(name.trim()); + } + + protected void handlePassword(PasswordCallback c) throws IOException + { + out.print(c.getPrompt()); + BufferedReader in = + new BufferedReader(new InputStreamReader(System.in)); + String pass = in.readLine(); + c.setPassword(pass.toCharArray()); + } + + protected void handleTextInput(TextInputCallback c) throws IOException + { + BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); + out.print(c.getPrompt()); + String text = in.readLine(); + if (text != null) + c.setText(text); + } + + protected void handleTextOutput(TextOutputCallback c) + { + out.print(c.getMessage()); + } +} diff --git a/libjava/classpath/gnu/javax/security/auth/callback/DefaultCallbackHandler.java b/libjava/classpath/gnu/javax/security/auth/callback/DefaultCallbackHandler.java new file mode 100644 index 000000000..df0360b2e --- /dev/null +++ b/libjava/classpath/gnu/javax/security/auth/callback/DefaultCallbackHandler.java @@ -0,0 +1,109 @@ +/* DefaultCallbackHandler.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.util.Locale; + +import javax.security.auth.callback.ChoiceCallback; +import javax.security.auth.callback.ConfirmationCallback; +import javax.security.auth.callback.LanguageCallback; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.TextInputCallback; +import javax.security.auth.callback.TextOutputCallback; + +/** + * This trivial implementation of {@link CallbackHandler} sets its + * {@link Callback} arguments to default values, with no user interaction. + */ +public class DefaultCallbackHandler extends AbstractCallbackHandler +{ + + // Constructor. + // ------------------------------------------------------------------------- + + public DefaultCallbackHandler() + { + super("DEFAULT"); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + protected void handleChoice(ChoiceCallback c) + { + c.setSelectedIndex(c.getDefaultChoice()); + } + + protected void handleConfirmation(ConfirmationCallback c) + { + if (c.getOptionType() == ConfirmationCallback.YES_NO_OPTION) + c.setSelectedIndex(ConfirmationCallback.NO); + else if (c.getOptionType() == ConfirmationCallback.YES_NO_CANCEL_OPTION) + c.setSelectedIndex(ConfirmationCallback.NO); + else if (c.getOptionType() == ConfirmationCallback.OK_CANCEL_OPTION) + c.setSelectedIndex(ConfirmationCallback.OK); + else + c.setSelectedIndex(c.getDefaultOption()); + } + + protected void handleLanguage(LanguageCallback c) + { + c.setLocale(Locale.getDefault()); + } + + protected void handleName(NameCallback c) + { + c.setName(System.getProperty("user.name")); + } + + protected void handlePassword(PasswordCallback c) + { + c.setPassword(new char[0]); + } + + protected void handleTextInput(TextInputCallback c) + { + c.setText(""); + } + + protected void handleTextOutput(TextOutputCallback c) + { + } +} diff --git a/libjava/classpath/gnu/javax/security/auth/callback/GnuCallbacks.java b/libjava/classpath/gnu/javax/security/auth/callback/GnuCallbacks.java new file mode 100644 index 000000000..9fd72f926 --- /dev/null +++ b/libjava/classpath/gnu/javax/security/auth/callback/GnuCallbacks.java @@ -0,0 +1,64 @@ +/* GnuCallbacks.java -- Provider for callback implementations. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.AccessController; +import java.security.PrivilegedAction; +import java.security.Provider; + +public final class GnuCallbacks extends Provider +{ + public GnuCallbacks() + { + super("GNU-CALLBACKS", 2.1, "Implementations of various callback handlers."); + + AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + put("CallbackHandler.Default", DefaultCallbackHandler.class.getName()); + put("CallbackHandler.Console", ConsoleCallbackHandler.class.getName()); + put("CallbackHandler.AWT", AWTCallbackHandler.class.getName()); + put("CallbackHandler.Swing", SwingCallbackHandler.class.getName()); + + return null; + } + }); + } +} diff --git a/libjava/classpath/gnu/javax/security/auth/callback/SwingCallbackHandler.java b/libjava/classpath/gnu/javax/security/auth/callback/SwingCallbackHandler.java new file mode 100644 index 000000000..c9d5b3eb5 --- /dev/null +++ b/libjava/classpath/gnu/javax/security/auth/callback/SwingCallbackHandler.java @@ -0,0 +1,587 @@ + /* SwingCallbackHandler.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.awt.Container; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import java.io.IOException; + +import java.util.Locale; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.ChoiceCallback; +import javax.security.auth.callback.ConfirmationCallback; +import javax.security.auth.callback.LanguageCallback; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.TextInputCallback; +import javax.security.auth.callback.TextOutputCallback; + +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JPasswordField; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.JTextField; +import javax.swing.ListSelectionModel; + +public class SwingCallbackHandler extends AbstractCallbackHandler +{ + public SwingCallbackHandler () + { + super ("SWING"); + } + + protected void handleChoice (final ChoiceCallback callback) + throws IOException + { + final JDialog dialog = new JDialog (); + dialog.setResizable (false); + Container content = dialog.getContentPane (); + GridBagLayout layout = new GridBagLayout (); + content.setLayout (layout); + JLabel prompt = new JLabel (callback.getPrompt (), JLabel.LEFT); + content.add (prompt, new GridBagConstraints (0, 0, 1, 1, 0, 0, + GridBagConstraints.WEST, + GridBagConstraints.NONE, + new Insets (5, 5, 5, 5), 5, 5)); + + String[] choices = callback.getChoices (); + final JList choicesList = new JList (choices); + JScrollPane choicesPane = new JScrollPane (choicesList, + JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, + JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + final int defaultChoice = callback.getDefaultChoice (); + choicesList.setSelectedIndex (defaultChoice); + choicesList.setSelectionMode (callback.allowMultipleSelections () + ? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION + : ListSelectionModel.SINGLE_SELECTION); + content.add (choicesPane, new GridBagConstraints (0, 1, 1, 1, 1.0, 1.0, + GridBagConstraints.CENTER, + GridBagConstraints.BOTH, + new Insets (0, 10, 0, 10), 5, 5)); + + JPanel confirmButtons = new JPanel (); + confirmButtons.setLayout (new FlowLayout (FlowLayout.RIGHT)); + JButton cancel = new JButton (messages.getString ("callback.cancel")); + JButton ok = new JButton (messages.getString ("callback.ok")); + confirmButtons.add (cancel); + confirmButtons.add (ok); + content.add (confirmButtons, new GridBagConstraints (0, 2, 1, 1, 0, 0, + GridBagConstraints.EAST, + GridBagConstraints.NONE, + new Insets (5, 5, 5, 5), + 0, 0)); + dialog.getRootPane ().setDefaultButton (ok); + + cancel.addActionListener (new ActionListener () + { + public void actionPerformed (final ActionEvent ae) + { + callback.setSelectedIndex (defaultChoice); + dialog.setVisible (false); + synchronized (callback) + { + callback.notify (); + } + } + }); + ok.addActionListener (new ActionListener () + { + public void actionPerformed (final ActionEvent ae) + { + if (callback.allowMultipleSelections ()) + { + int[] indices = choicesList.getSelectedIndices (); + if (indices != null && indices.length > 0) + callback.setSelectedIndexes (indices); + else + callback.setSelectedIndex (defaultChoice); + } + else + { + int selected = choicesList.getSelectedIndex (); + if (selected != -1) + callback.setSelectedIndex (selected); + else + callback.setSelectedIndex (defaultChoice); + } + dialog.setVisible (false); + synchronized (callback) + { + callback.notify (); + } + } + }); + + dialog.pack (); + dialog.setSize (new Dimension (400, 400)); + dialog.setVisible (true); + waitForInput (dialog, callback); + } + + protected void handleConfirmation (final ConfirmationCallback callback) + throws IOException + { + final JDialog dialog = new JDialog (); + switch (callback.getMessageType ()) + { + case ConfirmationCallback.ERROR: + dialog.setTitle (messages.getString ("callback.error")); + break; + case ConfirmationCallback.WARNING: + dialog.setTitle (messages.getString ("callback.warning")); + break; + case ConfirmationCallback.INFORMATION: + dialog.setTitle (messages.getString ("callback.information")); + break; + } + Container content = dialog.getContentPane (); + content.setLayout (new GridBagLayout ()); + + String prompt = callback.getPrompt (); + if (prompt != null) + { + content.add (new JLabel (prompt), + new GridBagConstraints (0, 0, 1, 1, 0, 0, + GridBagConstraints.WEST, + GridBagConstraints.NONE, + new Insets (5, 5, 5, 25), 0, 0)); + } + + final String[] options = callback.getOptions (); + ActionListener listener = new ActionListener () + { + public void actionPerformed (ActionEvent ae) + { + String cmd = ae.getActionCommand (); + if (options != null) + { + for (int i = 0; i < options.length; i++) + { + if (cmd.equals (options[i])) + { + callback.setSelectedIndex (i); + break; + } + } + } + else + { + if (cmd.equals ("cancel")) + callback.setSelectedIndex (ConfirmationCallback.CANCEL); + else if (cmd.equals ("okay")) + callback.setSelectedIndex (ConfirmationCallback.OK); + else if (cmd.equals ("yes")) + callback.setSelectedIndex (ConfirmationCallback.YES); + else if (cmd.equals ("no")) + callback.setSelectedIndex (ConfirmationCallback.NO); + } + dialog.setVisible (false); + synchronized (callback) + { + callback.notify (); + } + } + }; + + JPanel buttons = new JPanel (); + buttons.setLayout (new FlowLayout (FlowLayout.RIGHT)); + switch (callback.getOptionType ()) + { + case ConfirmationCallback.YES_NO_CANCEL_OPTION: + { + JButton cancel = new JButton (messages.getString ("callback.cancel")); + buttons.add (cancel); + cancel.setActionCommand ("cancel"); + cancel.addActionListener (listener); + } + /* Fall-through. */ + case ConfirmationCallback.YES_NO_OPTION: + { + JButton yes = new JButton (messages.getString ("callback.yes")); + JButton no = new JButton (messages.getString ("callback.no")); + buttons.add (no); + buttons.add (yes); + yes.setActionCommand ("yes"); + yes.addActionListener (listener); + no.setActionCommand ("no"); + no.addActionListener (listener); + dialog.getRootPane ().setDefaultButton (yes); + } + break; + case ConfirmationCallback.OK_CANCEL_OPTION: + { + JButton okay = new JButton (messages.getString ("callback.ok")); + JButton cancel = new JButton (messages.getString ("callback.cancel")); + buttons.add (cancel); + buttons.add (okay); + okay.setActionCommand ("okay"); + okay.addActionListener (listener); + cancel.setActionCommand ("cancel"); + cancel.addActionListener (listener); + dialog.getRootPane ().setDefaultButton (okay); + } + break; + case ConfirmationCallback.UNSPECIFIED_OPTION: + for (int i = 0; i < options.length; i++) + { + JButton button = new JButton (options[i]); + buttons.add (button); + button.setActionCommand (options[i]); + button.addActionListener (listener); + if (i == options.length - 1) + dialog.getRootPane ().setDefaultButton (button); + } + } + content.add (buttons, + new GridBagConstraints (0, GridBagConstraints.RELATIVE, + 1, 1, 1, 1, + GridBagConstraints.SOUTHEAST, + GridBagConstraints.BOTH, + new Insets (5, 5, 5, 5), 0, 0)); + dialog.setResizable (false); + dialog.pack (); + dialog.setVisible (true); + waitForInput (dialog, callback); + } + + protected void handleLanguage (final LanguageCallback callback) + throws IOException + { + Locale locale = Locale.getDefault (); + Locale[] locales = Locale.getAvailableLocales (); + String[] localeNames = new String[locales.length+1]; + int defaultIndex = 0; + for (int i = 0; i < locales.length; i++) + { + localeNames[i+1] = locales[i].getDisplayLanguage (locales[i]); + String country = locales[i].getDisplayCountry (locales[i]); + if (country.length () > 0) + localeNames[i+1] += " (" + country + ")"; + if (locales[i].equals (locale)) + defaultIndex = i; + } + locales[0] = locale; + localeNames[0] = locale.getDisplayLanguage (locale); + String country = locale.getDisplayCountry (locale); + if (country.length () > 0) + localeNames[0] += " (" + country + ")"; + ChoiceCallback cb = new ChoiceCallback (messages.getString ("callback.language"), + localeNames, 0, + false); + handleChoice (cb); + int selected = cb.getSelectedIndexes ()[0]; + if (selected > 0) + callback.setLocale (locales[selected - 1]); + else + callback.setLocale (locale); + } + + protected void handleName (final NameCallback callback) + throws IOException + { + final JDialog dialog = new JDialog (); + Container content = dialog.getContentPane (); + content.setLayout (new GridBagLayout ()); + + content.add (new JLabel (callback.getPrompt ()), + new GridBagConstraints (0, 0, 1, 1, 0, 0, + GridBagConstraints.NORTHEAST, + GridBagConstraints.VERTICAL, + new Insets (10, 10, 15, 5), 0, 0)); + + final JTextField name = new JTextField (); + name.setColumns (20); + String _name; + if ((_name = callback.getDefaultName ()) != null) + name.setText (_name); + content.add (name, new GridBagConstraints (1, 0, 1, 1, 1, 1, + GridBagConstraints.NORTHWEST, + GridBagConstraints.BOTH, + new Insets (10, 5, 15, 10), 0, 0)); + + ActionListener listener = new ActionListener () + { + public void actionPerformed (ActionEvent ae) + { + String cmd = ae.getActionCommand (); + if (cmd.equals ("okay")) + callback.setName (name.getText ()); + dialog.setVisible (false); + synchronized (callback) + { + callback.notify (); + } + } + }; + + JPanel buttons = new JPanel (); + buttons.setLayout (new FlowLayout (FlowLayout.RIGHT)); + JButton cancel = new JButton (messages.getString ("callback.cancel")); + JButton okay = new JButton (messages.getString ("callback.ok")); + cancel.setActionCommand ("cancel"); + cancel.addActionListener (listener); + buttons.add (cancel); + okay.setActionCommand ("okay"); + okay.addActionListener (listener); + buttons.add (okay); + content.add (buttons, new GridBagConstraints (0, 1, 2, 1, 0, 0, + GridBagConstraints.SOUTHEAST, + GridBagConstraints.NONE, + new Insets (0, 10, 10, 10), 0, 0)); + + dialog.setResizable (false); + dialog.pack (); + dialog.setVisible (true); + dialog.getRootPane ().setDefaultButton (okay); + waitForInput (dialog, callback); + } + + protected void handlePassword (final PasswordCallback callback) + throws IOException + { + final JDialog dialog = new JDialog (); + Container content = dialog.getContentPane (); + content.setLayout (new GridBagLayout ()); + + content.add (new JLabel (callback.getPrompt ()), + new GridBagConstraints (0, 0, 1, 1, 0, 0, + GridBagConstraints.NORTHEAST, + GridBagConstraints.VERTICAL, + new Insets (10, 10, 15, 5), 0, 0)); + + final JPasswordField password = new JPasswordField (); + password.setColumns (20); + password.setEchoChar (callback.isEchoOn () ? '\u0000' : '\u2022'); + content.add (password, new GridBagConstraints (1, 0, 1, 1, 1, 1, + GridBagConstraints.NORTHWEST, + GridBagConstraints.BOTH, + new Insets (10, 5, 15, 10), 0, 0)); + + ActionListener listener = new ActionListener () + { + public void actionPerformed (ActionEvent ae) + { + String cmd = ae.getActionCommand (); + if (cmd.equals ("okay")) + callback.setPassword (password.getPassword ()); + dialog.setVisible (false); + synchronized (callback) + { + callback.notify (); + } + } + }; + + JPanel buttons = new JPanel (); + buttons.setLayout (new FlowLayout (FlowLayout.RIGHT)); + JButton cancel = new JButton (messages.getString ("callback.cancel")); + JButton okay = new JButton (messages.getString ("callback.ok")); + cancel.setActionCommand ("cancel"); + cancel.addActionListener (listener); + buttons.add (cancel); + okay.setActionCommand ("okay"); + okay.addActionListener (listener); + buttons.add (okay); + content.add (buttons, new GridBagConstraints (0, 1, 2, 1, 0, 0, + GridBagConstraints.SOUTHEAST, + GridBagConstraints.NONE, + new Insets (0, 10, 10, 10), 0, 0)); + + dialog.setResizable (false); + dialog.pack (); + dialog.setVisible (true); + dialog.getRootPane ().setDefaultButton (okay); + waitForInput (dialog, callback); + } + + protected void handleTextInput (final TextInputCallback callback) + throws IOException + { + final JDialog dialog = new JDialog (); + Container content = dialog.getContentPane (); + content.setLayout (new GridBagLayout ()); + + content.add (new JLabel (callback.getPrompt ()), + new GridBagConstraints (0, 0, 1, 1, 0, 0, + GridBagConstraints.NORTHWEST, + GridBagConstraints.NONE, + new Insets (10, 10, 15, 5), 0, 0)); + + final JTextArea text = new JTextArea (24, 80); + text.setEditable (true); + String _text; + if ((_text = callback.getDefaultText ()) != null) + text.setText (_text); + text.setFont (new Font ("Monospaced", Font.PLAIN, 12)); + JScrollPane textPane = new JScrollPane (text, + JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, + JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + content.add (textPane, + new GridBagConstraints (0, 1, 1, 1, 1, 1, + GridBagConstraints.CENTER, + GridBagConstraints.BOTH, + new Insets (5, 10, 5, 10), 0, 0)); + + ActionListener listener = new ActionListener () + { + public void actionPerformed (ActionEvent ae) + { + String cmd = ae.getActionCommand (); + if (cmd.equals ("okay")) + callback.setText (text.getText ()); + dialog.setVisible (false); + synchronized (callback) + { + callback.notify (); + } + } + }; + + JPanel buttons = new JPanel (); + buttons.setLayout (new FlowLayout (FlowLayout.RIGHT)); + JButton cancel = new JButton (messages.getString ("callback.cancel")); + JButton okay = new JButton (messages.getString ("callback.ok")); + cancel.setActionCommand ("cancel"); + cancel.addActionListener (listener); + buttons.add (cancel); + okay.setActionCommand ("okay"); + okay.addActionListener (listener); + buttons.add (okay); + content.add (buttons, new GridBagConstraints (0, 2, 1, 1, 0, 0, + GridBagConstraints.SOUTHEAST, + GridBagConstraints.NONE, + new Insets (0, 10, 10, 10), 0, 0)); + + dialog.setResizable (true); + dialog.pack (); + dialog.setVisible (true); + dialog.getRootPane ().setDefaultButton (okay); + waitForInput (dialog, callback); + } + + protected void handleTextOutput (final TextOutputCallback callback) + throws IOException + { + final JDialog dialog = new JDialog (); + switch (callback.getMessageType ()) + { + case TextOutputCallback.ERROR: + dialog.setTitle (messages.getString ("callback.error")); + break; + case TextOutputCallback.WARNING: + dialog.setTitle (messages.getString ("callback.warning")); + break; + case TextOutputCallback.INFORMATION: + dialog.setTitle (messages.getString ("callback.information")); + break; + } + Container content = dialog.getContentPane (); + content.setLayout (new GridBagLayout ()); + + final JTextArea text = new JTextArea (24, 80); + text.setEditable (false); + text.setText (callback.getMessage ()); + text.setFont (new Font ("Monospaced", Font.PLAIN, 12)); + JScrollPane textPane = new JScrollPane (text, + JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, + JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + content.add (textPane, + new GridBagConstraints (0, 0, 1, 1, 1, 1, + GridBagConstraints.CENTER, + GridBagConstraints.BOTH, + new Insets (10, 10, 5, 10), 0, 0)); + + ActionListener listener = new ActionListener () + { + public void actionPerformed (ActionEvent ae) + { + dialog.setVisible (false); + synchronized (callback) + { + callback.notify (); + } + } + }; + + JButton okay = new JButton (messages.getString ("callback.ok")); + okay.setActionCommand ("okay"); + okay.addActionListener (listener); + content.add (okay, new GridBagConstraints (0, 1, 1, 1, 0, 0, + GridBagConstraints.SOUTHEAST, + GridBagConstraints.NONE, + new Insets (0, 10, 10, 10), 0, 0)); + + dialog.setResizable (true); + dialog.pack (); + dialog.setVisible (true); + dialog.getRootPane ().setDefaultButton (okay); + waitForInput (dialog, callback); + } + + private void waitForInput (JDialog dialog, Callback callback) + { + synchronized (callback) + { + while (dialog.isVisible ()) + { + try + { + callback.wait (1000); + } + catch (InterruptedException ignored) + { + } + } + } + dialog.dispose (); + } +} diff --git a/libjava/classpath/gnu/javax/security/auth/login/ConfigFileParser.java b/libjava/classpath/gnu/javax/security/auth/login/ConfigFileParser.java new file mode 100644 index 000000000..5c4c4261f --- /dev/null +++ b/libjava/classpath/gnu/javax/security/auth/login/ConfigFileParser.java @@ -0,0 +1,346 @@ +/* ConfigFileParser.java -- JAAS Login Configuration default syntax parser + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.security.auth.login; + +import gnu.java.security.Configuration; + +import java.io.IOException; +import java.io.Reader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; + +import javax.security.auth.login.AppConfigurationEntry; + +/** + * A parser that knows how to interpret JAAS Login Module Configuration files + * written in the default syntax which is interpreted as adhering to + * the following grammar: + * + *

    + *   CONFIG              ::= APP_OR_OTHER_ENTRY+
    + *   APP_OR_OTHER_ENTRY  ::= APP_NAME_OR_OTHER JAAS_CONFIG_BLOCK
    + *   APP_NAME_OR_OTHER   ::= APP_NAME
    + *                         | 'other'
    + *   JAAS_CONFIG_BLOCK   ::= '{' (LOGIN_MODULE_ENTRY ';')+ '}' ';'
    + *   LOGIN_MODULE_ENTRY  ::= MODULE_CLASS FLAG MODULE_OPTION* ';'
    + *   FLAG                ::= 'required'
    + *                         | 'requisite'
    + *                         | 'sufficient'
    + *                         | 'optional'
    + *   MODULE_OPTION       ::= PARAM_NAME '=' PARAM_VALUE
    + *
    + *   APP_NAME     ::= JAVA_IDENTIFIER
    + *   MODULE_CLASS ::= JAVA_IDENTIFIER ('.' JAVA_IDENTIFIER)*
    + *   PARAM_NAME   ::= STRING
    + *   PARAM_VALUE  ::= '"' STRING '"' | ''' STRING ''' | STRING
    + * 
    + * + *

    This parser handles UTF-8 entities when used as APP_NAME and PARAM_VALUE. + * It also checks for the use of Java identifiers used in MODULE_CLASS, thus + * minimizing the risks of having {@link java.lang.ClassCastException}s thrown + * at runtime due to syntactically invalid names.

    + * + *

    In the above context, a JAVA_IDENTIFIER is a sequence of tokens, + * separated by the character '.'. Each of these tokens obeys the following:

    + * + *
      + *
    1. its first character yields true when used as an input to + * the {@link java.lang.Character#isJavaIdentifierStart(char)}, and
    2. + *
    3. all remaining characters, yield true when used as an + * input to {@link java.lang.Character#isJavaIdentifierPart(char)}.
    4. + *
    + */ +public final class ConfigFileParser +{ + private static final Logger log = Logger.getLogger(ConfigFileParser.class.getName()); + private ConfigFileTokenizer cft; + private Map map = new HashMap(); + + // default 0-arguments constructor + + /** + * Returns the parse result as a {@link Map} where the keys are application + * names, and the entries are {@link List}s of {@link AppConfigurationEntry} + * entries, one for each login module entry, in the order they were + * encountered, for that application name in the just parsed configuration + * file. + */ + public Map getLoginModulesMap() + { + return map; + } + + /** + * Parses the {@link Reader}'s contents assuming it is in the default + * syntax. + * + * @param r the {@link Reader} whose contents are assumed to be a JAAS Login + * Configuration Module file written in the default syntax. + * @throws IOException if an exception occurs while parsing the input. + */ + public void parse(Reader r) throws IOException + { + initParser(r); + + while (parseAppOrOtherEntry()) + { + /* do nothing */ + } + } + + private void initParser(Reader r) throws IOException + { + map.clear(); + + cft = new ConfigFileTokenizer(r); + } + + /** + * @return true if an APP_OR_OTHER_ENTRY was correctly parsed. + * Returns false otherwise. + * @throws IOException if an exception occurs while parsing the input. + */ + private boolean parseAppOrOtherEntry() throws IOException + { + int c = cft.nextToken(); + if (c == ConfigFileTokenizer.TT_EOF) + return false; + + if (c != ConfigFileTokenizer.TT_WORD) + { + cft.pushBack(); + return false; + } + + String appName = cft.sval; + if (Configuration.DEBUG) + log.fine("APP_NAME_OR_OTHER = " + appName); + if (cft.nextToken() != '{') + abort("Missing '{' after APP_NAME_OR_OTHER"); + + List lmis = new ArrayList(); + while (parseACE(lmis)) + { + /* do nothing */ + } + + c = cft.nextToken(); + if (c != '}') + abort("Was expecting '}' but found " + (char) c); + + c = cft.nextToken(); + if (c != ';') + abort("Was expecting ';' but found " + (char) c); + + List listOfACEs = (List) map.get(appName); + if (listOfACEs == null) + { + listOfACEs = new ArrayList(); + map.put(appName, listOfACEs); + } + listOfACEs.addAll(lmis); + return !appName.equalsIgnoreCase("other"); + } + + /** + * @return true if a LOGIN_MODULE_ENTRY was correctly parsed. + * Returns false otherwise. + * @throws IOException if an exception occurs while parsing the input. + */ + private boolean parseACE(List listOfACEs) throws IOException + { + int c = cft.nextToken(); + if (c != ConfigFileTokenizer.TT_WORD) + { + cft.pushBack(); + return false; + } + + String clazz = validateClassName(cft.sval); + if (Configuration.DEBUG) + log.fine("MODULE_CLASS = " + clazz); + + if (cft.nextToken() != ConfigFileTokenizer.TT_WORD) + abort("Was expecting FLAG but found none"); + + String flag = cft.sval; + if (Configuration.DEBUG) + log.fine("DEBUG: FLAG = " + flag); + AppConfigurationEntry.LoginModuleControlFlag f = null; + if (flag.equalsIgnoreCase("required")) + f = AppConfigurationEntry.LoginModuleControlFlag.REQUIRED; + else if (flag.equalsIgnoreCase("requisite")) + f = AppConfigurationEntry.LoginModuleControlFlag.REQUISITE; + else if (flag.equalsIgnoreCase("sufficient")) + f = AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT; + else if (flag.equalsIgnoreCase("optional")) + f = AppConfigurationEntry.LoginModuleControlFlag.OPTIONAL; + else + abort("Unknown Flag: " + flag); + + Map options = new HashMap(); + String paramName, paramValue; + c = cft.nextToken(); + while (c != ';') + { + if (c != ConfigFileTokenizer.TT_WORD) + abort("Was expecting PARAM_NAME but got '" + ((char) c) + "'"); + + paramName = cft.sval; + if (Configuration.DEBUG) + log.fine("PARAM_NAME = " + paramName); + if (cft.nextToken() != '=') + abort("Missing '=' after PARAM_NAME"); + + c = cft.nextToken(); + if (c != '"' && c != '\'') + { + if (Configuration.DEBUG) + log.fine("Was expecting a quoted string but got no quote character." + + " Assume unquoted string"); + } + paramValue = expandParamValue(cft.sval); + if (Configuration.DEBUG) + log.fine("PARAM_VALUE = " + paramValue); + options.put(paramName, paramValue); + + c = cft.nextToken(); + } + AppConfigurationEntry ace = new AppConfigurationEntry(clazz, f, options); + if (Configuration.DEBUG) + log.fine("LOGIN_MODULE_ENTRY = " + ace); + listOfACEs.add(ace); + return true; + } + + private void abort(String m) throws IOException + { + if (Configuration.DEBUG) + { + log.fine(m); + log.fine("Map (so far) = " + String.valueOf(map)); + } + throw new IOException(m); + } + + private String validateClassName(String cn) throws IOException + { + if (cn.startsWith(".") || cn.endsWith(".")) + abort("MODULE_CLASS MUST NOT start or end with a '.'"); + + String[] tokens = cn.split("\\."); + for (int i = 0; i < tokens.length; i++) + { + String t = tokens[i]; + if (! Character.isJavaIdentifierStart(t.charAt(0))) + abort("Class name [" + cn + + "] contains an invalid sub-package identifier: " + t); + + // we dont check the rest of the characters for isJavaIdentifierPart() + // because that's what the tokenizer does. + } + + return cn; + } + + /** + * The documentation of the {@link javax.security.auth.login.Configuration} + * states that: "...If a String in the form, ${system.property}, occurs in + * the value, it will be expanded to the value of the system property.". + * This method ensures this is the case. If such a string can not be expanded + * then it is left AS IS, assuming the LoginModule knows what to do with it. + * + *

    IMPORTANT: This implementation DOES NOT handle embedded ${} + * constructs. + * + * @param s the raw parameter value, incl. eventually strings of the form + * ${system.property}. + * @return the input string with every occurence of + * ${system.property} replaced with the value of the + * corresponding System property at the time of this method invocation. If + * the string is not a known System property name, then the complete sequence + * (incl. the ${} characters are passed AS IS. + */ + private String expandParamValue(String s) + { + String result = s; + try + { + int searchNdx = 0; + while (searchNdx < result.length()) + { + int i = s.indexOf("${", searchNdx); + if (i == -1) + break; + + int j = s.indexOf("}", i + 2); + if (j == -1) + { + if (Configuration.DEBUG) + log.fine("Found a ${ prefix with no } suffix. Ignore"); + break; + } + + String sysPropName = s.substring(i + 2, j); + if (Configuration.DEBUG) + log.fine("Found a reference to System property " + sysPropName); + String sysPropValue = System.getProperty(sysPropName); + if (Configuration.DEBUG) + log.fine("Resolved " + sysPropName + " to '" + sysPropValue + "'"); + if (sysPropValue != null) + { + result = s.substring(0, i) + sysPropValue + s.substring(j + 1); + searchNdx = i + sysPropValue.length(); + } + else + searchNdx = j + 1; + } + } + catch (Exception x) + { + if (Configuration.DEBUG) + log.fine("Exception (ignored) while expanding " + s + ": " + x); + } + + return result; + } +} diff --git a/libjava/classpath/gnu/javax/security/auth/login/ConfigFileTokenizer.java b/libjava/classpath/gnu/javax/security/auth/login/ConfigFileTokenizer.java new file mode 100644 index 000000000..fc35bf772 --- /dev/null +++ b/libjava/classpath/gnu/javax/security/auth/login/ConfigFileTokenizer.java @@ -0,0 +1,246 @@ +/* ConfigFileTokenizer.java -- JAAS Login Configuration default syntax tokenizer + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.security.auth.login; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.Configuration; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.Reader; +import java.util.logging.Logger; + +/** + * A UTF-8 friendly, JAAS Login Module Configuration file tokenizer written in + * the deault syntax. This class emulates, to a certain extent, the behavior of + * a {@link java.io.StreamTokenizer} instance st, when set as + * follows: + * + *

    + *  st.resetSyntax();
    + *  st.lowerCaseMode(false);
    + *  st.slashSlashComments(true);
    + *  st.slashStarComments(true);
    + *  st.eolIsSignificant(false);
    + *  st.wordChars('_', '_');
    + *  st.wordChars('$', '$');
    + *  st.wordChars('A', 'Z');
    + *  st.wordChars('a', 'z');
    + *  st.wordChars('0', '9');
    + *  st.wordChars('.', '.');
    + *  st.whitespaceChars(' ', ' ');
    + *  st.whitespaceChars('\t', '\t');
    + *  st.whitespaceChars('\f', '\f');
    + *  st.whitespaceChars('\r', '\r');
    + *  st.whitespaceChars('\n', '\n');
    + *  st.quoteChar('"');
    + *  st.quoteChar('\'');
    + *  
    + * + *

    The most important (negative) difference with a + * {@link java.io.StreamTokenizer} is that this tokenizer does not properly + * handle C++ and Java // style comments in the middle of the line. It only + * ignores them if/when found at the start of the line.

    + */ +public class ConfigFileTokenizer +{ + private static final Logger log = Logger.getLogger(ConfigFileParser.class.getName()); + /** A constant indicating that the end of the stream has been read. */ + public static final int TT_EOF = -1; + /** A constant indicating that a word token has been read. */ + public static final int TT_WORD = -3; + /** A constant indicating that no tokens have been read yet. */ + private static final int TT_NONE = -4; + + public String sval; + public int ttype; + + private BufferedReader br; + boolean initialised; + private CPStringBuilder sb; + private int sbNdx; + + // Constructor(s) + // -------------------------------------------------------------------------- + + /** Trivial constructor. */ + ConfigFileTokenizer(Reader r) + { + super(); + + br = r instanceof BufferedReader ? (BufferedReader) r : new BufferedReader(r); + initialised = false; + } + + // Class methods + // -------------------------------------------------------------------------- + + // Instance methods + // -------------------------------------------------------------------------- + + public int nextToken() throws IOException + { + if (!initialised) + init(); + + if (sbNdx >= sb.length()) + return TT_EOF; + + skipWhitespace(); + + if (sbNdx >= sb.length()) + return TT_EOF; + + int endNdx; + if (Character.isJavaIdentifierPart(sb.charAt(sbNdx))) + { + endNdx = sbNdx + 1; + while (Character.isJavaIdentifierPart(sb.charAt(endNdx)) + || sb.charAt(endNdx) == '.') + endNdx++; + + ttype = TT_WORD; + sval = sb.substring(sbNdx, endNdx); + sbNdx = endNdx; + return ttype; + } + + int c = sb.charAt(sbNdx); + if (c == '{' || c == '}' || c == ';' || c == '=') + { + ttype = c; + sbNdx++; + return ttype; + } + + if (c == '"' || c == '\'') + { + ttype = c; + String quote = sb.substring(sbNdx, sbNdx + 1); + int i = sbNdx + 1; + while (true) + { + // find a candidate + endNdx = sb.indexOf(quote, i); + if (endNdx == -1) + abort("Missing closing quote: " + quote); + + // found one; is it escaped? + if (sb.charAt(endNdx - 1) != '\\') + break; + + i++; + continue; + } + + endNdx++; + sval = sb.substring(sbNdx, endNdx); + sbNdx = endNdx; + return ttype; + } + + abort("Unknown character: " + sb.charAt(sbNdx)); + return Integer.MIN_VALUE; + } + + public void pushBack() + { + sbNdx -= ttype != TT_WORD ? 1 : sval.length(); + } + + private void init() throws IOException + { + sb = new CPStringBuilder(); + String line; + while ((line = br.readLine()) != null) + { + line = line.trim(); + if (line.length() == 0) + continue; + + if (line.startsWith("#") || line.startsWith("//")) + continue; + + sb.append(line).append(" "); + } + + sbNdx = 0; + sval = null; + ttype = TT_NONE; + + initialised = true; + } + + private void skipWhitespace() throws IOException + { + int endNdx; + while (sbNdx < sb.length()) + if (Character.isWhitespace(sb.charAt(sbNdx))) + { + sbNdx++; + while (sbNdx < sb.length() && Character.isWhitespace(sb.charAt(sbNdx))) + sbNdx++; + + continue; + } + else if (sb.charAt(sbNdx) == '/' && sb.charAt(sbNdx + 1) == '*') + { + endNdx = sb.indexOf("*/", sbNdx + 2); + if (endNdx == -1) + abort("Missing closing */ sequence"); + + sbNdx = endNdx + 2; + continue; + } + else + break; + } + + private void abort(String m) throws IOException + { + if (Configuration.DEBUG) + { + log.fine(m); + log.fine("sb = " + sb); + log.fine("sbNdx = " + sbNdx); + } + throw new IOException(m); + } +} diff --git a/libjava/classpath/gnu/javax/security/auth/login/GnuConfiguration.java b/libjava/classpath/gnu/javax/security/auth/login/GnuConfiguration.java new file mode 100644 index 000000000..20d8f3afd --- /dev/null +++ b/libjava/classpath/gnu/javax/security/auth/login/GnuConfiguration.java @@ -0,0 +1,466 @@ +/* GnuConfiguration.java -- GNU Classpath implementation of JAAS Configuration + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.security.auth.login; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.Security; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; + +import javax.security.auth.AuthPermission; +import javax.security.auth.login.AppConfigurationEntry; +import javax.security.auth.login.Configuration; + +/** + * An implementation of the {@link Configuration} class which interprets JAAS + * Login Configuration files written in the default syntax described in + * the publicly available documentation of that class. A more formal definition + * of this syntax is as follows: + * + *
    + *   CONFIG              ::= APP_OR_OTHER_ENTRY+
    + *   APP_OR_OTHER_ENTRY  ::= APP_NAME_OR_OTHER JAAS_CONFIG_BLOCK
    + *   APP_NAME_OR_OTHER   ::= APP_NAME
    + *                         | 'other'
    + *   JAAS_CONFIG_BLOCK   ::= '{' (LOGIN_MODULE_ENTRY ';')+ '}' ';'
    + *   LOGIN_MODULE_ENTRY  ::= MODULE_CLASS FLAG MODULE_OPTION* ';'
    + *   FLAG                ::= 'required'
    + *                         | 'requisite'
    + *                         | 'sufficient'
    + *                         | 'optional'
    + *   MODULE_OPTION       ::= PARAM_NAME '=' PARAM_VALUE
    + *
    + *   APP_NAME     ::= JAVA_IDENTIFIER
    + *   MODULE_CLASS ::= JAVA_IDENTIFIER ('.' JAVA_IDENTIFIER)*
    + *   PARAM_NAME   ::= STRING
    + *   PARAM_VALUE  ::= '"' STRING '"' | ''' STRING ''' | STRING
    + * 
    + * + *

    This implementation will specifically attempt to process one or more + * Login Configuration files in the following locations, and when found parse + * them and merge their contents. The locations, and the order in which they are + * investigated, follows:

    + * + *
      + *
    1. If the following Security properties: + * java.security.auth.login.config.url.N, where N + * is a digit, from 1 to an arbitrary number, are defined, then + * the value of each of those properties will be considered as a JAAS Login + * Configuration file written in the default syntax. This implementation will + * attempt parsing all such files. + * + *

      It is worth noting the following: + *

        + *
      • The GNU Classpath security file, named classpath.security, + * where all Security properties are encoded, is usually located in + * /usr/local/classpath/lib/security folder.
      • + * + *
      • The numbers used in the properties + * java.security.auth.login.config.url.N MUST be sequential, + * with no breaks in-between.
      • + *
      + *

      + * + *

      If at least one of the designated Configuration files was found, and + * was parsed correctly, then no other location will be inspected.

    2. + * + *
    3. If the System property named java.security.auth.login.config + * is not null or empty, its contents are then interpreted as a URL to a + * JAAS Login Configuration file written in the default syntax. + * + *

      If this System property is defined, and the file it refers to was + * parsed correctly, then no other location will be inspected.

    4. + * + *
    5. If a file named .java.login.config or java.login.config + * (in that order) is found in the location referenced by the value of the + * System property user.home, then that file is parsed as a JAAS Login + * Configuration written in the default syntax.
    6. + * + *
    7. If none of the above resulted in a correctly parsed JAAS Login + * Configuration file, then this implementation will install a Null + * Configuration which basically does not recognize any Application.
    8. + *
    + */ +public final class GnuConfiguration extends Configuration +{ + private static final Logger log = Logger.getLogger(GnuConfiguration.class.getName()); + /** + * The internal map of login modules keyed by application name. Each entry in + * this map is a {@link List} of {@link AppConfigurationEntry}s for that + * application name. + */ + private Map loginModulesMap; + /** Our reference to our default syntax parser. */ + private ConfigFileParser cp; + + // Constructor(s) + // -------------------------------------------------------------------------- + + /** Trivial 0-arguments Constructor. */ + public GnuConfiguration() + { + super(); + + loginModulesMap = new HashMap(); + cp = new ConfigFileParser(); + init(); + } + + // Class methods + // -------------------------------------------------------------------------- + + // Instance methods + // -------------------------------------------------------------------------- + + // Configuration abstract methods implementation ---------------------------- + + /* (non-Javadoc) + * @see javax.security.auth.login.Configuration#getAppConfigurationEntry(java.lang.String) + */ + public AppConfigurationEntry[] getAppConfigurationEntry(String appName) + { + if (appName == null) + return null; + + appName = appName.trim(); + if (appName.length() == 0) + return null; + + List loginModules = (List) loginModulesMap.get(appName); + if (loginModules == null || loginModules.size() == 0) + return null; + + if (gnu.java.security.Configuration.DEBUG) + log.fine(appName + " -> " + loginModules.size() + " entry(ies)"); + return (AppConfigurationEntry[]) loginModules.toArray(new AppConfigurationEntry[0]); + } + + /** + * Refreshes and reloads this Configuration. + * + *

    This method causes this Configuration object to refresh / + * reload its contents following the locations and logic described above in + * the class documentation section.

    + * + * @throws SecurityException if the caller does not have an + * {@link AuthPermission} for the action named + * refreshLoginConfiguration. + * @see AuthPermission + */ + public void refresh() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new AuthPermission("refreshLoginConfiguration")); + + loginModulesMap.clear(); + init(); + } + + // helper methods ----------------------------------------------------------- + + /** + * Attempts to find and parse JAAS Login Configuration file(s) written in + * the default syntax. The locations searched are as descibed in the class + * documentation. + */ + private void init() + { + if (processSecurityProperties()) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("Using login configuration defined by Security property(ies)"); + } + else if (processSystemProperty()) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("Using login configuration defined by System property"); + } + else if (processUserHome()) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("Using login configuration defined in ${user.home}"); + } + else + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("No login configuration file found"); + } + } + + /** + * Attempts to locate and parse one or more JAAS Login Configuration files + * defined as the values of the Security properties + * java.security.auth.login.config.url.N. + * + * @return true if it succeeds, and false + * otherwsie. + */ + private boolean processSecurityProperties() + { + boolean result = false; + int counter = 0; + String s; + while (true) + try + { + counter++; + s = Security.getProperty("java.security.auth.login.config.url." + + counter); + if (s == null) + break; + + s = s.trim(); + if (s.length() != 0) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("java.security.auth.login.config.url." + counter + + " = " + s); + parseConfig(getInputStreamFromURL(s)); + result = true; + } + } + catch (Throwable t) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("Exception while handling Security property at #" + + counter + ". Continue: " + t); + } + return result; + } + + /** + * Attempts to open a designated string as a well-formed {@link URL}. If a + * {@link MalformedURLException} occurs, this method then tries to open that + * string as a {@link File} (with the same name). If it succeeds, an + * {@link InputStream} is constructed and returned. + * + * @param s + * the designated name of either a {@link URL} or a {@link File} + * assumed to contain a JAAS Login Configuration in the default + * syntax. + * @return an {@link InputStream} around the data source. + * @throws IOException + * if an exception occurs during the operation. + */ + private InputStream getInputStreamFromURL(String s) throws IOException + { + InputStream result = null; + try + { + URL url = new URL(s); + result = url.openStream(); + } + catch (MalformedURLException x) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("Failed opening as URL: " + s + ". Will try as File"); + result = new FileInputStream(s); + } + return result; + } + + /** + * Attempts to locate and parse a JAAS Login Configuration file defined as the + * value of the System property java.security.auth.login.config. + * + * @return true if it succeeds, and false + * otherwsie. + */ + private boolean processSystemProperty() + { + boolean result = false; + try + { + String s = System.getProperty("java.security.auth.login.config"); + if (s != null) + { + s = s.trim(); + if (s.length() != 0) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("java.security.auth.login.config = " + s); + parseConfig(getInputStreamFromURL(s)); + result = true; + } + } + } + catch (Throwable t) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("Exception while handling System property. Continue: " + t); + } + return result; + } + + /** + * Attempts to locate and parse a JAAS Login Configuration file named either + * as .java.login.config or java.login.config (without the + * leading dot) in the folder referenced by the System property + * user.home. + * + * @return true if it succeeds, and false + * otherwsie. + */ + private boolean processUserHome() + { + boolean result = false; + try + { + File userHome = getUserHome(); + if (userHome == null) + return result; + + File jaasFile; + jaasFile = getConfigFromUserHome(userHome, ".java.login.config"); + if (jaasFile == null) + jaasFile = getConfigFromUserHome(userHome, "java.login.config"); + + if (jaasFile == null) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("Login Configuration file, in " + userHome + + ", does not exist or is inaccessible"); + return result; + } + + FileInputStream fis = new FileInputStream(jaasFile); + parseConfig(fis); + result = true; + } + catch (Throwable t) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("Exception (ignored) while handling ${user.home}: " + t); + } + return result; + } + + private void parseConfig(InputStream configStream) throws IOException + { + cp.parse(new InputStreamReader(configStream, "UTF-8")); + Map loginModulesMap = cp.getLoginModulesMap(); + mergeLoginModules(loginModulesMap); + } + + private void mergeLoginModules(Map otherLoginModules) + { + if (otherLoginModules == null || otherLoginModules.size() < 1) + return; + + for (Iterator it = otherLoginModules.keySet().iterator(); it.hasNext();) + { + String appName = (String) it.next(); + List thatListOfACEs = (List) otherLoginModules.get(appName); + if (thatListOfACEs == null || thatListOfACEs.size() < 1) + continue; + + List thisListsOfACEs = (List) loginModulesMap.get(appName); + if (thisListsOfACEs == null) + loginModulesMap.put(appName, thatListOfACEs); + else + thisListsOfACEs.addAll(thatListOfACEs); + } + } + + private File getUserHome() + { + String uh = System.getProperty("user.home"); + if (uh == null || uh.trim().length() == 0) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("User home path is not set or is empty"); + return null; + } + uh = uh.trim(); + File result = new File(uh); + if (! result.exists()) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("User home '" + uh + "' does not exist"); + return null; + } + if (! result.isDirectory()) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("User home '" + uh + "' is not a directory"); + return null; + } + if (! result.canRead()) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("User home '" + uh + "' is not readable"); + return null; + } + return result; + } + + private File getConfigFromUserHome(File userHome, String fileName) + { + File result = new File(userHome, fileName); + if (! result.exists()) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("File '" + fileName + "' does not exist in user's home"); + return null; + } + if (! result.isFile()) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("File '" + fileName + "' in user's home is not a file"); + return null; + } + if (! result.canRead()) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("File '" + fileName + "' in user's home is not readable"); + return null; + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/sound/AudioSecurityManager.java b/libjava/classpath/gnu/javax/sound/AudioSecurityManager.java new file mode 100644 index 000000000..1daea2db5 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/AudioSecurityManager.java @@ -0,0 +1,112 @@ +/* AudioSecurityManager.java -- Manages Security requests for Sound classes. + + Copyright (C) 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.sound; + +import javax.sound.sampled.AudioPermission; + +/** + * This class handles security requests for classes in the Sound API. + * + * A class that needs to check against a particular permission type may use this + * class to query the SecurityManager. + * + * For example, to check for a read permission, a class can simply pass the + * Permission.READ constant to + * {@link #checkPermissions(gnu.javax.sound.AudioSecurityManager.Permission))}, + * like the following code demonstrates: + * + *
    + * AudioSecurityManager.checkPermissions(Permission.PLAY);
    + * 
    + * + * If there is need to query for all the defined permissions type, the constant + * Permission.ALL can be used. In alternative, the + * {@link #checkPermissions()} is presented as a shorthand. + * + * @author Mario Torre + */ +public class AudioSecurityManager +{ + /** + * Defines a common set of permission allowed by the specification. + */ + public static enum Permission + { + PLAY, RECORD, ALL + } + + /** + * Shorthand to checkPermissions(Permission.ALL). + */ + public static final void checkPermissions() + { + checkPermissions(Permission.ALL); + } + + /** + * Query the SecurityManager agains the given + * Permission. + * + * @param permission + */ + public static final void checkPermissions(Permission permission) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + { + String perm = null; + switch (permission) + { + case PLAY: + perm = "play"; + break; + + case RECORD: + perm = "record"; + break; + + case ALL: default: + perm = "*"; + break; + } + + sm.checkPermission(new AudioPermission(perm)); + } + } +} diff --git a/libjava/classpath/gnu/javax/sound/midi/alsa/AlsaInputPortDevice.java b/libjava/classpath/gnu/javax/sound/midi/alsa/AlsaInputPortDevice.java new file mode 100644 index 000000000..d37a8fd6b --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/midi/alsa/AlsaInputPortDevice.java @@ -0,0 +1,130 @@ +/* AlsaInputPortDevice.java -- ALSA MIDI In Port + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.sound.midi.alsa; + +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Receiver; +import javax.sound.midi.Transmitter; +import gnu.javax.sound.midi.alsa.AlsaMidiDeviceProvider.AlsaPortInfo; + +/** + * ALSA MIDI In Port. + * + * @author Anthony Green (green@redhat.com) + * + */ +public class AlsaInputPortDevice extends AlsaPortDevice +{ + + AlsaInputPortDevice (AlsaPortInfo info) + { + super(info); + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#open() + */ + public void open() throws MidiUnavailableException + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#close() + */ + public void close() + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#isOpen() + */ + public boolean isOpen() + { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getMicrosecondPosition() + */ + public long getMicrosecondPosition() + { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getMaxReceivers() + */ + public int getMaxReceivers() + { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getMaxTransmitters() + */ + public int getMaxTransmitters() + { + // TODO Auto-generated method stub + return 1; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getReceiver() + */ + public Receiver getReceiver() throws MidiUnavailableException + { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getTransmitter() + */ + public Transmitter getTransmitter() throws MidiUnavailableException + { + return new AlsaTransmitter(); + } +} diff --git a/libjava/classpath/gnu/javax/sound/midi/alsa/AlsaMidiDeviceProvider.java b/libjava/classpath/gnu/javax/sound/midi/alsa/AlsaMidiDeviceProvider.java new file mode 100644 index 000000000..33181b6d5 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/midi/alsa/AlsaMidiDeviceProvider.java @@ -0,0 +1,216 @@ +/* AlsaMidiDeviceProvider.java -- The ALSA MIDI Device Provider + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.sound.midi.alsa; + +import gnu.classpath.Configuration; + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiDevice.Info; +import javax.sound.midi.spi.MidiDeviceProvider; + +/** + * Provide ALSA MIDI devices. + * + * @author Anthony Green (green@redhat.com) + * + */ +public class AlsaMidiDeviceProvider extends MidiDeviceProvider +{ + /** + * Abstract base for ALSA specific MIDI device info. + * + * @author Anthony Green (green@redhat.com) + * + */ + private static abstract class AlsaInfo extends Info + { + /** + * Create an ALSA specific MIDI device info object. + * + * @param name the device name + * @param description the device description + */ + public AlsaInfo(String name, String description) + { + super(name, "Alsa", description, "0.0"); + } + + abstract MidiDevice getDevice (); + } + + /** + * ALSA MIDI Port. + * + * @author Anthony Green (green@redhat.com) + * + */ + public static abstract class AlsaPortInfo extends AlsaInfo + { + long client; + long port; + + /** + * Create ALSA MIDI In Port. + * + * @param name the device name + * @param description the device description + * @param client the client ID + * @param port the port ID + */ + public AlsaPortInfo(String name, String description, long client, long port) + { + super(name, description); + this.client = client; + this.port = port; + } + } + + /** + * ALSA Sequencer specific info. + * + * @author Anthony Green (green@redhat.com) + * + */ + private static class AlsaSequencerInfo extends AlsaInfo + { + public AlsaSequencerInfo(String name, String description) + { + super(name, description); + } + + MidiDevice getDevice() + { + return AlsaMidiSequencerDevice.getInstance(); + } + } + + /** + * ALSA MIDI In Port. + * + * @author Anthony Green (green@redhat.com) + * + */ + private static class AlsaInputPortInfo extends AlsaPortInfo + { + public AlsaInputPortInfo(String name, String description, long client, long port) + { + super(name, description, client, port); + } + + MidiDevice getDevice() + { + return new AlsaInputPortDevice(this); + } + } + + /** + * ALSA MIDI Out Port. + * + * @author Anthony Green (green@redhat.com) + * + */ + private static class AlsaOutputPortInfo extends AlsaPortInfo + { + public AlsaOutputPortInfo(String name, String description, long client, long port) + { + super(name, description, client, port); + } + + MidiDevice getDevice() + { + return new AlsaOutputPortDevice(this); + } + } + + private static AlsaInfo[] infos; + + private static native AlsaInfo[] getInputDeviceInfo_(); + private static native AlsaInfo[] getOutputDeviceInfo_(); + + /** + * Initialize the ALSA system + */ + private static native void init_(); + + static + { + if (Configuration.INIT_LOAD_LIBRARY) + { + System.loadLibrary("gjsmalsa"); + } + + init_(); + + AlsaInfo inputs[] = getInputDeviceInfo_(); + AlsaInfo outputs[] = getOutputDeviceInfo_(); + + infos = new AlsaInfo[inputs.length + outputs.length + 1]; + infos[0] = new AlsaSequencerInfo ("/dev/snd/seq", "ALSA Sequencer"); + System.arraycopy(inputs, 0, infos, 1, inputs.length); + System.arraycopy(outputs, 0, infos, 1 + inputs.length, outputs.length); + } + + public AlsaMidiDeviceProvider() + { + // Nothing. + } + + /* (non-Javadoc) + * @see javax.sound.midi.spi.MidiDeviceProvider#getDeviceInfo() + */ + public Info[] getDeviceInfo() + { + return infos; + } + + /* (non-Javadoc) + * @see javax.sound.midi.spi.MidiDeviceProvider#getDevice(javax.sound.midi.MidiDevice.Info) + */ + public MidiDevice getDevice(Info info) + { + for (int i = 0; i < infos.length; i++) + { + if (info.equals(infos[i])) + { + return infos[i].getDevice(); + } + } + throw new IllegalArgumentException("Don't recognize MIDI device " + info); + } +} diff --git a/libjava/classpath/gnu/javax/sound/midi/alsa/AlsaMidiSequencerDevice.java b/libjava/classpath/gnu/javax/sound/midi/alsa/AlsaMidiSequencerDevice.java new file mode 100644 index 000000000..3603bb5a7 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/midi/alsa/AlsaMidiSequencerDevice.java @@ -0,0 +1,515 @@ +/* AlsaMidiSequencerDevice.java -- The ALSA MIDI sequencer device + Copyright (C) 2005, 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.sound.midi.alsa; + +import java.io.IOException; +import java.io.InputStream; + +import javax.sound.midi.ControllerEventListener; +import javax.sound.midi.InvalidMidiDataException; +import javax.sound.midi.MetaEventListener; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Receiver; +import javax.sound.midi.Sequence; +import javax.sound.midi.Sequencer; +import javax.sound.midi.Track; +import javax.sound.midi.Transmitter; + +/** + * The ALSA MIDI sequencer device. This is a singleton device. + * + * @author green@redhat.com + * + */ +public class AlsaMidiSequencerDevice implements Sequencer +{ + // The singleton instance. + public final static AlsaMidiSequencerDevice instance = new AlsaMidiSequencerDevice(); + + // A pointer to a native chunk of memory + private long nativeState; + + // The sequence to process + private Sequence sequence; + + /** + * A private constructor. There should only be one instance of this + * device. + */ + private AlsaMidiSequencerDevice() + { + super(); + } + + /** + * Return the sequencer singleton. + * + * @return the sequencer singleton + */ + public static AlsaMidiSequencerDevice getInstance() + { + return instance; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#setSequence(javax.sound.midi.Sequence) + */ + public void setSequence(Sequence seq) throws InvalidMidiDataException + { + sequence = seq; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#setSequence(java.io.InputStream) + */ + public void setSequence(InputStream istream) throws IOException, + InvalidMidiDataException + { + // TODO Auto-generated method stub + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#getSequence() + */ + public Sequence getSequence() + { + return sequence; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#start() + */ + public void start() + { + // TODO Auto-generated method stub + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#stop() + */ + public void stop() + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#isRunning() + */ + public boolean isRunning() + { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#startRecording() + */ + public void startRecording() + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#stopRecording() + */ + public void stopRecording() + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#isRecording() + */ + public boolean isRecording() + { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#recordEnable(javax.sound.midi.Track, int) + */ + public void recordEnable(Track track, int channel) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#recordDisable(javax.sound.midi.Track) + */ + public void recordDisable(Track track) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#getTempoInBPM() + */ + public float getTempoInBPM() + { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#setTempoInBPM(float) + */ + public void setTempoInBPM(float bpm) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#getTempoInMPQ() + */ + public float getTempoInMPQ() + { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#setTempoInMPQ(float) + */ + public void setTempoInMPQ(float mpq) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#setTempoFactor(float) + */ + public void setTempoFactor(float factor) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#getTempoFactor() + */ + public float getTempoFactor() + { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#getTickLength() + */ + public long getTickLength() + { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#getTickPosition() + */ + public long getTickPosition() + { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#setTickPosition(long) + */ + public void setTickPosition(long tick) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#getMicrosecondLength() + */ + public long getMicrosecondLength() + { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#getMicrosecondPosition() + */ + public long getMicrosecondPosition() + { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#setMicrosecondPosition(long) + */ + public void setMicrosecondPosition(long microsecond) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#setMasterSyncMode(javax.sound.midi.Sequencer.SyncMode) + */ + public void setMasterSyncMode(SyncMode sync) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#getMasterSyncMode() + */ + public SyncMode getMasterSyncMode() + { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#getMasterSyncModes() + */ + public SyncMode[] getMasterSyncModes() + { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#setSlaveSyncMode(javax.sound.midi.Sequencer.SyncMode) + */ + public void setSlaveSyncMode(SyncMode sync) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#getSlaveSyncMode() + */ + public SyncMode getSlaveSyncMode() + { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#getSlaveSyncModes() + */ + public SyncMode[] getSlaveSyncModes() + { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#setTrackMute(int, boolean) + */ + public void setTrackMute(int track, boolean mute) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#getTrackMute(int) + */ + public boolean getTrackMute(int track) + { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#setTrackSolo(int, boolean) + */ + public void setTrackSolo(int track, boolean solo) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#getTrackSolo(int) + */ + public boolean getTrackSolo(int track) + { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#addMetaEventListener(javax.sound.midi.MetaEventListener) + */ + public boolean addMetaEventListener(MetaEventListener listener) + { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#removeMetaEventListener(javax.sound.midi.MetaEventListener) + */ + public void removeMetaEventListener(MetaEventListener listener) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#addControllerEventListener(javax.sound.midi.ControllerEventListener, int[]) + */ + public int[] addControllerEventListener(ControllerEventListener listener, + int[] controllers) + { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#removeControllerEventListener(javax.sound.midi.ControllerEventListener, int[]) + */ + public int[] removeControllerEventListener(ControllerEventListener listener, + int[] controllers) + { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getDeviceInfo() + */ + public Info getDeviceInfo() + { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#open() + */ + public void open() throws MidiUnavailableException + { + synchronized(this) + { + // Check to see if we're open already. + if (nativeState != 0) + return; + + nativeState = open_(); + } + } + + /** + * Allocate the native state object, and open the sequencer. + * + * @return a long representation of a pointer to the nativeState. + */ + private native long open_(); + + /** + * Close the sequencer and free the native state object. + */ + private native void close_(long nativeState); + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#close() + */ + public void close() + { + synchronized(this) + { + close_(nativeState); + nativeState = 0; + } + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#isOpen() + */ + public boolean isOpen() + { + synchronized(this) + { + return (nativeState != 0); + } + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getMaxReceivers() + */ + public int getMaxReceivers() + { + return -1; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getMaxTransmitters() + */ + public int getMaxTransmitters() + { + return -1; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getReceiver() + */ + public Receiver getReceiver() throws MidiUnavailableException + { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getTransmitter() + */ + public Transmitter getTransmitter() throws MidiUnavailableException + { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/libjava/classpath/gnu/javax/sound/midi/alsa/AlsaOutputPortDevice.java b/libjava/classpath/gnu/javax/sound/midi/alsa/AlsaOutputPortDevice.java new file mode 100644 index 000000000..9140d59ad --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/midi/alsa/AlsaOutputPortDevice.java @@ -0,0 +1,131 @@ +/* AlsaOutputPortDevice.java -- ALSA MIDI Output Port Device + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.sound.midi.alsa; + +import gnu.javax.sound.midi.alsa.AlsaMidiDeviceProvider.AlsaPortInfo; + +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Receiver; +import javax.sound.midi.Transmitter; + +/** + * ALSA MIDI Out Device + * + * @author Anthony Green (green@redhat.com) + * + */ +public class AlsaOutputPortDevice extends AlsaPortDevice +{ + AlsaOutputPortDevice (AlsaPortInfo info) + { + super(info); + } + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#open() + */ + public void open() throws MidiUnavailableException + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#close() + */ + public void close() + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#isOpen() + */ + public boolean isOpen() + { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getMicrosecondPosition() + */ + public long getMicrosecondPosition() + { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getMaxReceivers() + */ + public int getMaxReceivers() + { + // TODO Auto-generated method stub + return 1; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getMaxTransmitters() + */ + public int getMaxTransmitters() + { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getReceiver() + */ + public Receiver getReceiver() throws MidiUnavailableException + { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getTransmitter() + */ + public Transmitter getTransmitter() throws MidiUnavailableException + { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/libjava/classpath/gnu/javax/sound/midi/alsa/AlsaPortDevice.java b/libjava/classpath/gnu/javax/sound/midi/alsa/AlsaPortDevice.java new file mode 100644 index 000000000..f55941ba5 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/midi/alsa/AlsaPortDevice.java @@ -0,0 +1,150 @@ +/* AlsaPortDevice.java -- ALSA MIDI Port Devices + Copyright (C) 2005, 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.sound.midi.alsa; + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiMessage; +import javax.sound.midi.Receiver; +import javax.sound.midi.Transmitter; + +import gnu.javax.sound.midi.alsa.AlsaMidiDeviceProvider.AlsaPortInfo; + +/** + * ALSA Port Device + * + * @author Anthony Green (green@redhat.com) + * + */ +public abstract class AlsaPortDevice implements MidiDevice +{ + /** + * The ALSA Receiver class. + * + * @author Anthony Green (green@redhat.com) + * + */ + public class AlsaReceiver implements Receiver + { + /* (non-Javadoc) + * @see javax.sound.midi.Receiver#send(javax.sound.midi.MidiMessage, long) + */ + public void send(MidiMessage message, long timeStamp) + throws IllegalStateException + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Receiver#close() + */ + public void close() + { + // TODO Auto-generated method stub + + } + } + + AlsaMidiDeviceProvider.AlsaPortInfo info; + + public AlsaPortDevice (AlsaPortInfo info) + { + this.info = info; + } + + public Info getDeviceInfo() + { + return info; + } + + native void run_receiver_thread_ (long client, long port, Receiver receiver); + + /** + * The ALSA Transmitter class. + * + * @author Anthony Green (green@redhat.com) + * + */ + protected class AlsaTransmitter implements Transmitter, Runnable + { + private Receiver receiver; + + public void run() + { + run_receiver_thread_ (info.client, info.port, receiver); + } + + /* (non-Javadoc) + * @see javax.sound.midi.Transmitter#setReceiver(javax.sound.midi.Receiver) + */ + public void setReceiver(Receiver receiver) + { + synchronized (this) + { + this.receiver = receiver; + } + + // Create the processing thread + new Thread(this).start(); + } + + /* (non-Javadoc) + * @see javax.sound.midi.Transmitter#getReceiver() + */ + public Receiver getReceiver() + { + synchronized (this) + { + return receiver; + } + } + + /* (non-Javadoc) + * @see javax.sound.midi.Transmitter#close() + */ + public void close() + { + synchronized (this) + { + receiver.close(); + receiver = null; + } + } + } +} diff --git a/libjava/classpath/gnu/javax/sound/midi/dssi/DSSIMidiDeviceProvider.java b/libjava/classpath/gnu/javax/sound/midi/dssi/DSSIMidiDeviceProvider.java new file mode 100644 index 000000000..605c6dfb7 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/midi/dssi/DSSIMidiDeviceProvider.java @@ -0,0 +1,171 @@ +/* DSSIMidiDeviceProvider.java -- DSSI Device Provider + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.sound.midi.dssi; + +import java.util.ArrayList; +import java.util.List; +import java.io.File; +import java.io.FilenameFilter; + +import gnu.classpath.Configuration; +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiDevice.Info; +import javax.sound.midi.spi.MidiDeviceProvider; + +/** + * A DSSI MIDI device provider. + * + * DSSI (pronounced "dizzy") is an API for audio plugins, with particular + * application for software synthesis plugins with native user interfaces. + * + * Read about DSSI at http://dssi.sourceforge.net + * + * @author Anthony Green (green@redhat.com) + * + */ +public class DSSIMidiDeviceProvider extends MidiDeviceProvider +{ + /** + * The MidiDevice.Info specialized for DSSI synthesizers. + * + * @author Anthony Green (green@redhat.com) + * + */ + private static class DSSIInfo extends Info + { + String soname; + long index; + + public DSSIInfo(String name, String vendor, String description, + String version, String soname, long index) + { + super(name, vendor, description, version); + this.soname = soname; + this.index = index; + } + } + + static native long dlopen_(String soname); + static native void dlclose_(long sohandle); + static native long getDSSIHandle_(long sohandle, long index); + static native String getDSSIName_(long handle); + static native String getDSSICopyright_(long handle); + static native String getDSSIVendor_(long handle); + static native String getDSSILabel_(long handle); + + private static List examineLibrary(String soname) + { + List list = new ArrayList(); + long index = 0; + long handle; + + long sohandle = dlopen_(soname); + if (sohandle == 0) + return list; + do + { + handle = getDSSIHandle_(sohandle, index); + if (handle == 0) + break; + String name = getDSSILabel_(handle); + String copyright = getDSSICopyright_(handle); + String label = getDSSIName_(handle); + String vendor = getDSSIVendor_(handle); + list.add(new DSSIInfo(name, vendor, label, + "DSSI-1", soname, index)); + index++; + } while (true); + + // Close the library and free memory + dlclose_(sohandle); + + return list; + } + + private static DSSIInfo[] infos; + + static + { + if (Configuration.INIT_LOAD_LIBRARY) + System.loadLibrary("gjsmdssi"); + + File dssidir = new File("/usr/lib/dssi/"); + String sofiles[] = dssidir.list(new FilenameFilter() + { + public boolean accept(File dir, String n) + { + return n.endsWith(".so"); + } + }); + List ilist = new ArrayList(); + for (int i = 0; i < sofiles.length; i++) + ilist.addAll(examineLibrary(new File(dssidir, sofiles[i]).getAbsolutePath())); + infos = (DSSIInfo[]) ilist.toArray(new DSSIInfo[ilist.size()]); + } + + public DSSIMidiDeviceProvider() + { + // Empty. + } + + /* Return the Info array. + * @see javax.sound.midi.spi.MidiDeviceProvider#getDeviceInfo() + */ + public Info[] getDeviceInfo() + { + return infos; + } + + /* Get a MIDI Device for info. + * @see javax.sound.midi.spi.MidiDeviceProvider#getDevice(javax.sound.midi.MidiDevice.Info) + */ + public MidiDevice getDevice(Info info) + { + for (int i = 0; i < infos.length; i++) + { + if (info.equals(infos[i])) + { + return new DSSISynthesizer(infos[i], + infos[i].soname, + infos[i].index); + } + } + throw new IllegalArgumentException("Don't recognize MIDI device " + info); + } +} diff --git a/libjava/classpath/gnu/javax/sound/midi/dssi/DSSISynthesizer.java b/libjava/classpath/gnu/javax/sound/midi/dssi/DSSISynthesizer.java new file mode 100644 index 000000000..9472ee4ad --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/midi/dssi/DSSISynthesizer.java @@ -0,0 +1,742 @@ +/* DSSISynthesizer.java -- DSSI Synthesizer Provider + Copyright (C) 2005, 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.sound.midi.dssi; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.sound.midi.Instrument; +import javax.sound.midi.MidiChannel; +import javax.sound.midi.MidiMessage; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.midi.Receiver; +import javax.sound.midi.ShortMessage; +import javax.sound.midi.Soundbank; +import javax.sound.midi.SoundbankResource; +import javax.sound.midi.Synthesizer; +import javax.sound.midi.Transmitter; +import javax.sound.midi.VoiceStatus; + +/** + * DSSI soft-synth support. + * + * All DSSI soft-synths are expected to be installed in /usr/lib/dssi. + * + * @author Anthony Green (green@redhat.com) + * + */ +public class DSSISynthesizer implements Synthesizer +{ + /** + * The DSSI Instrument class. + * + * @author Anthony Green (green@redhat.com) + * + */ + class DSSIInstrument extends Instrument + { + DSSIInstrument (Soundbank soundbank, Patch patch, String name) + { + super (soundbank, patch, name, null); + } + + /* @see javax.sound.midi.SoundbankResource#getData() + */ + public Object getData() + { + return null; + } + + } + +/** + * DSSISoundbank holds all instruments. + * + * @author Anthony Green (green@redhat.com) + * + */ + class DSSISoundbank implements Soundbank + { + private String name; + private String description; + private List instruments = new ArrayList(); + private List resources = new ArrayList(); + private String vendor; + private String version; + + public DSSISoundbank(String name, String description, String vendor, String version) + { + this.name = name; + this.description = description; + this.vendor = vendor; + this.version = version; + } + + void add(Instrument instrument) + { + instruments.add(instrument); + } + + /* @see javax.sound.midi.Soundbank#getName() + */ + public String getName() + { + return name; + } + + /* @see javax.sound.midi.Soundbank#getVersion() + */ + public String getVersion() + { + return version; + } + + /* @see javax.sound.midi.Soundbank#getVendor() + */ + public String getVendor() + { + return vendor; + } + + /* @see javax.sound.midi.Soundbank#getDescription() + */ + public String getDescription() + { + return description; + } + + /* @see javax.sound.midi.Soundbank#getResources() + */ + public SoundbankResource[] getResources() + { + return (SoundbankResource[]) + resources.toArray(new SoundbankResource[resources.size()]); + } + + /* @see javax.sound.midi.Soundbank#getInstruments() + */ + public Instrument[] getInstruments() + { + return (Instrument[]) + instruments.toArray(new Instrument[instruments.size()]); + } + + /* @see javax.sound.midi.Soundbank#getInstrument(javax.sound.midi.Patch) + */ + public Instrument getInstrument(Patch patch) + { + Iterator itr = instruments.iterator(); + + while (itr.hasNext()) + { + Instrument i = (Instrument) itr.next(); + if (i.getPatch().equals(patch)) + return i; + } + + return null; + } + } + +/** + * The Receiver class receives all MIDI messages from a connected + * Transmitter. + * + * @author Anthony Green (green@redhat.com) + * + */ + class DSSIReceiver implements Receiver + { + /* (non-Javadoc) + * @see javax.sound.midi.Receiver#send(javax.sound.midi.MidiMessage, long) + */ + public void send(MidiMessage message, long timeStamp) + throws IllegalStateException + { + if (message instanceof ShortMessage) + { + ShortMessage smessage = (ShortMessage) message; + + switch (message.getStatus()) + { + case ShortMessage.NOTE_ON: + int velocity = smessage.getData2(); + if (velocity > 0) + channels[smessage.getChannel()].noteOn(smessage.getData1(), + smessage.getData2()); + else + channels[smessage.getChannel()].noteOff(smessage.getData1()); + break; + case ShortMessage.CONTROL_CHANGE: + channels[smessage.getChannel()].controlChange(smessage.getData1(), + smessage.getData2()); + break; + default: + System.out.println ("Unhandled message: " + message.getStatus()); + break; + } + } + } + + /* (non-Javadoc) + * @see javax.sound.midi.Receiver#close() + */ + public void close() + { + // TODO Auto-generated method stub + } + + } + + static native void noteOn_(long handle, int channel, int noteNumber, int velocity); + static native void noteOff_(long handle, int channel, int noteNumber, int velocity); + static native void setPolyPressure_(long handle, int channel, int noteNumber, int pressure); + static native int getPolyPressure_(long handle, int channel, int noteNumber); + static native void controlChange_(long handle, int channel, int control, int value); + static native void open_(long handle); + static native void close_(long handle); + static native String getProgramName_(long handle, int index); + static native int getProgramBank_(long handle, int index); + static native int getProgramProgram_(long handle, int index); + static native void selectProgram_(long handle, int bank, int program); + + /** + * @author Anthony Green (green@redhat.com) + * + */ + public class DSSIMidiChannel implements MidiChannel + { + int channel = 0; + + /** + * Default contructor. + */ + public DSSIMidiChannel(int channel) + { + super(); + this.channel = channel; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#noteOn(int, int) + */ + public void noteOn(int noteNumber, int velocity) + { + noteOn_(sohandle, channel, noteNumber, velocity); + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#noteOff(int, int) + */ + public void noteOff(int noteNumber, int velocity) + { + noteOff_(sohandle, channel, noteNumber, velocity); + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#noteOff(int) + */ + public void noteOff(int noteNumber) + { + noteOff_(sohandle, channel, noteNumber, -1); + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#setPolyPressure(int, int) + */ + public void setPolyPressure(int noteNumber, int pressure) + { + setPolyPressure_(sohandle, channel, noteNumber, pressure); + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#getPolyPressure(int) + */ + public int getPolyPressure(int noteNumber) + { + return getPolyPressure_(sohandle, channel, noteNumber); + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#setChannelPressure(int) + */ + public void setChannelPressure(int pressure) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#getChannelPressure() + */ + public int getChannelPressure() + { + // TODO Auto-generated method stub + return 0; + } + + /* @see javax.sound.midi.MidiChannel#controlChange(int, int) */ + public void controlChange(int controller, int value) + { + controlChange_(sohandle, channel, controller, value); + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#getController(int) + */ + public int getController(int controller) + { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#programChange(int) + */ + public void programChange(int program) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#programChange(int, int) + */ + public void programChange(int bank, int program) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#getProgram() + */ + public int getProgram() + { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#setPitchBend(int) + */ + public void setPitchBend(int bend) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#getPitchBend() + */ + public int getPitchBend() + { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#resetAllControllers() + */ + public void resetAllControllers() + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#allNotesOff() + */ + public void allNotesOff() + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#allSoundOff() + */ + public void allSoundOff() + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#localControl(boolean) + */ + public boolean localControl(boolean on) + { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#setMono(boolean) + */ + public void setMono(boolean on) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#getMono() + */ + public boolean getMono() + { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#setOmni(boolean) + */ + public void setOmni(boolean on) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#getOmni() + */ + public boolean getOmni() + { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#setMute(boolean) + */ + public void setMute(boolean mute) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#getMute() + */ + public boolean getMute() + { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#setSolo(boolean) + */ + public void setSolo(boolean solo) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#getSolo() + */ + public boolean getSolo() + { + // TODO Auto-generated method stub + return false; + } + + } + + long sohandle; + long handle; + private Info info; + + MidiChannel channels[] = new MidiChannel[16]; + + // The list of known soundbanks, and the default one. + List soundbanks = new ArrayList(); + DSSISoundbank defaultSoundbank; + + /** + * Create a DSSI Synthesizer. + * + * @param info the DSSIInfo for this soft-synth + * @param soname the name of the .so file for this DSSI synth + * @param index the DSSI index for this soft-synth + */ + public DSSISynthesizer(Info info, String soname, long index) + { + super(); + this.info = info; + sohandle = DSSIMidiDeviceProvider.dlopen_(soname); + handle = DSSIMidiDeviceProvider.getDSSIHandle_(sohandle, index); + channels[0] = new DSSIMidiChannel(0); + defaultSoundbank = new DSSISoundbank("name", "description", + "vendor", "version"); + soundbanks.add(defaultSoundbank); + + int i = 0; + String name; + do + { + name = getProgramName_(sohandle, i); + if (name != null) + { + defaultSoundbank. + add(new DSSIInstrument(defaultSoundbank, + new Patch(getProgramBank_(sohandle, i), + getProgramProgram_(sohandle, i)), + name)); + i++; + } + } while (name != null); + } + + /* (non-Javadoc) + * @see javax.sound.midi.Synthesizer#getMaxPolyphony() + */ + public int getMaxPolyphony() + { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Synthesizer#getLatency() + */ + public long getLatency() + { + // DSSI and LADSPA provide no way to determine the latency. + // Let's just return 0 for now. + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Synthesizer#getChannels() + */ + public MidiChannel[] getChannels() + { + return channels; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Synthesizer#getVoiceStatus() + */ + public VoiceStatus[] getVoiceStatus() + { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Synthesizer#isSoundbankSupported(javax.sound.midi.Soundbank) + */ + public boolean isSoundbankSupported(Soundbank soundbank) + { + // TODO Auto-generated method stub + return false; + } + + /* @see javax.sound.midi.Synthesizer#loadInstrument(javax.sound.midi.Instrument) + */ + public boolean loadInstrument(Instrument instrument) + { + // FIXME: perhaps this isn't quite right. It can probably + // be in any soundbank. + if (instrument.getSoundbank() != defaultSoundbank) + throw new IllegalArgumentException ("Synthesizer doesn't support this instrument's soundbank"); + + Patch patch = instrument.getPatch(); + selectProgram_(sohandle, patch.getBank(), patch.getProgram()); + return true; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Synthesizer#unloadInstrument(javax.sound.midi.Instrument) + */ + public void unloadInstrument(Instrument instrument) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Synthesizer#remapInstrument(javax.sound.midi.Instrument, javax.sound.midi.Instrument) + */ + public boolean remapInstrument(Instrument from, Instrument to) + { + // TODO Auto-generated method stub + return false; + } + + /* @see javax.sound.midi.Synthesizer#getDefaultSoundbank() + */ + public Soundbank getDefaultSoundbank() + { + return defaultSoundbank; + } + + /* @see javax.sound.midi.Synthesizer#getAvailableInstruments() + */ + public Instrument[] getAvailableInstruments() + { + List instruments = new ArrayList(); + Iterator itr = soundbanks.iterator(); + while (itr.hasNext()) + { + Soundbank sb = (Soundbank) itr.next(); + Instrument ins[] = sb.getInstruments(); + for (int i = 0; i < ins.length; i++) + instruments.add(ins[i]); + } + return (Instrument[]) + instruments.toArray(new Instrument[instruments.size()]); + } + + /* (non-Javadoc) + * @see javax.sound.midi.Synthesizer#getLoadedInstruments() + */ + public Instrument[] getLoadedInstruments() + { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Synthesizer#loadAllInstruments(javax.sound.midi.Soundbank) + */ + public boolean loadAllInstruments(Soundbank soundbank) + { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Synthesizer#unloadAllInstruments(javax.sound.midi.Soundbank) + */ + public void unloadAllInstruments(Soundbank soundbank) + { + // TODO Auto-generated method stub + } + + /* (non-Javadoc) + * @see javax.sound.midi.Synthesizer#loadInstruments(javax.sound.midi.Soundbank, javax.sound.midi.Patch[]) + */ + public boolean loadInstruments(Soundbank soundbank, Patch[] patchList) + { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Synthesizer#unloadInstruments(javax.sound.midi.Soundbank, javax.sound.midi.Patch[]) + */ + public void unloadInstruments(Soundbank soundbank, Patch[] patchList) + { + // TODO Auto-generated method stub + + } + + /* @see javax.sound.midi.MidiDevice#getDeviceInfo() + */ + public Info getDeviceInfo() + { + return info; + } + + /* @see javax.sound.midi.MidiDevice#open() + */ + public void open() throws MidiUnavailableException + { + open_(sohandle); + } + + /* @see javax.sound.midi.MidiDevice#close() + */ + public void close() + { + close_(sohandle); + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#isOpen() + */ + public boolean isOpen() + { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getMicrosecondPosition() + */ + public long getMicrosecondPosition() + { + // TODO Auto-generated method stub + return 0; + } + + /* @see javax.sound.midi.MidiDevice#getMaxReceivers() + */ + public int getMaxReceivers() + { + return 1; + } + + /* @see javax.sound.midi.MidiDevice#getMaxTransmitters() + */ + public int getMaxTransmitters() + { + return 0; + } + + /* @see javax.sound.midi.MidiDevice#getReceiver() + */ + public Receiver getReceiver() throws MidiUnavailableException + { + return new DSSIReceiver(); + } + + /* @see javax.sound.midi.MidiDevice#getTransmitter() + */ + public Transmitter getTransmitter() throws MidiUnavailableException + { + return null; + } +} diff --git a/libjava/classpath/gnu/javax/sound/midi/file/ExtendedMidiFileFormat.java b/libjava/classpath/gnu/javax/sound/midi/file/ExtendedMidiFileFormat.java new file mode 100644 index 000000000..4b065f3dc --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/midi/file/ExtendedMidiFileFormat.java @@ -0,0 +1,77 @@ +/* ExtendedMidiFileFormat.java -- extended with track count info. + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.sound.midi.file; + +/** + * ExtendedMidiFileFormat is a package private class that simply + * adds the number of MIDI tracks for the MidiFileFormat class. + * + * @author Anthony Green (green@redhat.com) + */ +class ExtendedMidiFileFormat + extends javax.sound.midi.MidiFileFormat +{ + private int ntracks; + + /** + * Get the number of tracks for this MIDI file. + * + * @return the number of tracks for this MIDI file + */ + public int getNumberTracks() + { + return ntracks; + } + + /** + * Create an ExtendedMidiFileFormat object from the given parameters. + * + * @param type the MIDI file type (0, 1, or 2) + * @param divisionType the MIDI file division type + * @param resolution the MIDI file timing resolution + * @param bytes the MIDI file size in bytes + * @param microseconds the MIDI file length in microseconds + * @param ntracks the number of tracks + */ + public ExtendedMidiFileFormat(int type, float divisionType, int resolution, + int bytes, long microseconds, int ntracks) + { + super(type, divisionType, resolution, bytes, microseconds); + this.ntracks = ntracks; + } +} diff --git a/libjava/classpath/gnu/javax/sound/midi/file/MidiDataInputStream.java b/libjava/classpath/gnu/javax/sound/midi/file/MidiDataInputStream.java new file mode 100644 index 000000000..d91970b9f --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/midi/file/MidiDataInputStream.java @@ -0,0 +1,83 @@ +/* MidiDataInputStream.java -- adds variable length MIDI ints + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.sound.midi.file; + +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * MidiDataInputStream is simply a DataInputStream with the addition + * of special variable length int reading as defined by the MIDI spec. + * + * @author Anthony Green (green@redhat.com) + */ +public class MidiDataInputStream + extends DataInputStream +{ + /** + * Create a MidiDataInputStream. + */ + public MidiDataInputStream(InputStream is) + { + super(is); + } + + /** + * Read an int encoded in the MIDI-style variable length + * encoding format. + * + * @return an int + */ + public int readVariableLengthInt() + throws IOException + { + int c, value = readByte(); + + if ((value & 0x80) != 0) + { + value &= 0x7F; + do + { + value = (value << 7) + ((c = readByte()) & 0x7F); + } while ((c & 0x80) != 0); + } + + return value; + } +} diff --git a/libjava/classpath/gnu/javax/sound/midi/file/MidiDataOutputStream.java b/libjava/classpath/gnu/javax/sound/midi/file/MidiDataOutputStream.java new file mode 100644 index 000000000..79c66e8a2 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/midi/file/MidiDataOutputStream.java @@ -0,0 +1,114 @@ +/* MidiDataOutputStream.java -- adds variable length MIDI ints + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.sound.midi.file; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * MidiDataOutputStream is simply a DataOutputStream with the addition + * of special variable length int writing as defined by the MIDI spec. + * + * @author Anthony Green (green@redhat.com) + */ +public class MidiDataOutputStream + extends DataOutputStream +{ + /** + * Create a MidiDataOutputStream. + */ + public MidiDataOutputStream(OutputStream os) + { + super(os); + } + + /** + * Return the length of a variable length encoded int without + * writing it out. + * + * @return the length of the encoding + */ + public int variableLengthIntLength (int value) + { + int length = 0; + int buffer = value & 0x7F; + + while ((value >>= 7) != 0) + { + buffer <<= 8; + buffer |= ((value & 0x7F) | 0x80); + } + + while (true) + { + length++; + if ((buffer & 0x80) != 0) + buffer >>>= 8; + else + break; + } + + return length; + } + + /** + * Write an int encoded in the MIDI-style variable length + * encoding format. + */ + public synchronized void writeVariableLengthInt (int value) + throws IOException + { + int buffer = value & 0x7F; + + while ((value >>= 7) != 0) + { + buffer <<= 8; + buffer |= ((value & 0x7F) | 0x80); + } + + while (true) + { + writeByte(buffer & 0xff); + if ((buffer & 0x80) != 0) + buffer >>>= 8; + else + break; + } + } +} diff --git a/libjava/classpath/gnu/javax/sound/midi/file/MidiFileReader.java b/libjava/classpath/gnu/javax/sound/midi/file/MidiFileReader.java new file mode 100644 index 000000000..fb2a472fa --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/midi/file/MidiFileReader.java @@ -0,0 +1,378 @@ +/* MidiFileReader.java -- Read MIDI files. + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.sound.midi.file; + +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +import javax.sound.midi.InvalidMidiDataException; +import javax.sound.midi.MetaMessage; +import javax.sound.midi.MidiEvent; +import javax.sound.midi.MidiFileFormat; +import javax.sound.midi.MidiMessage; +import javax.sound.midi.Sequence; +import javax.sound.midi.ShortMessage; +import javax.sound.midi.SysexMessage; +import javax.sound.midi.Track; + +/** + * A MIDI file reader. + * + * This code reads MIDI file types 0 and 1. + * + * There are many decent documents on the web describing the MIDI file + * format. I didn't bother looking for the official document. If it + * exists, I'm not even sure if it is freely available. We should + * update this comment if we find out anything helpful here. + * + * @author Anthony Green (green@redhat.com) + * + */ +public class MidiFileReader extends javax.sound.midi.spi.MidiFileReader +{ + /* Get the MidiFileFormat for the given input stream. + * @see javax.sound.midi.spi.MidiFileReader#getMidiFileFormat(java.io.InputStream) + */ + public MidiFileFormat getMidiFileFormat(InputStream in) + throws InvalidMidiDataException, IOException + { + DataInputStream din; + if (in instanceof DataInputStream) + din = (DataInputStream) in; + else + din = new DataInputStream(in); + + int type, ntracks, division, resolution, bytes; + float divisionType; + + if (din.readInt() != 0x4d546864) // "MThd" + throw new InvalidMidiDataException("Invalid MIDI chunk header."); + + bytes = din.readInt(); + if (bytes < 6) + throw new + InvalidMidiDataException("Invalid MIDI chunk header length: " + bytes); + + type = din.readShort(); + if (type < 0 || type > 2) + throw new + InvalidMidiDataException("Invalid MIDI file type value: " + type); + + ntracks = din.readShort(); + if (ntracks <= 0) + throw new + InvalidMidiDataException("Invalid number of MIDI tracks: " + ntracks); + + division = din.readShort(); + if ((division & 0x8000) != 0) + { + division = -((division >>> 8) & 0xFF); + switch (division) + { + case 24: + divisionType = Sequence.SMPTE_24; + break; + + case 25: + divisionType = Sequence.SMPTE_25; + break; + + case 29: + divisionType = Sequence.SMPTE_30DROP; + break; + + case 30: + divisionType = Sequence.SMPTE_30; + break; + + default: + throw new + InvalidMidiDataException("Invalid MIDI frame division type: " + + division); + } + resolution = division & 0xff; + } + else + { + divisionType = Sequence.PPQ; + resolution = division & 0x7fff; + } + + // If we haven't read every byte in the header now, just skip the rest. + din.skip(bytes - 6); + + return new ExtendedMidiFileFormat(type, divisionType, resolution, + MidiFileFormat.UNKNOWN_LENGTH, + MidiFileFormat.UNKNOWN_LENGTH, ntracks); + } + + /* Get the MidiFileFormat from the given URL. + * @see javax.sound.midi.spi.MidiFileReader#getMidiFileFormat(java.net.URL) + */ + public MidiFileFormat getMidiFileFormat(URL url) + throws InvalidMidiDataException, IOException + { + InputStream is = url.openStream(); + try + { + return getMidiFileFormat(is); + } + finally + { + is.close(); + } + } + + /* Get the MidiFileFormat from the given file. + * @see javax.sound.midi.spi.MidiFileReader#getMidiFileFormat(java.io.File) + */ + public MidiFileFormat getMidiFileFormat(File file) + throws InvalidMidiDataException, IOException + { + InputStream is = new FileInputStream(file); + try + { + return getMidiFileFormat(is); + } + finally + { + is.close(); + } + } + + /* Get the MIDI Sequence found in this input stream. + * @see javax.sound.midi.spi.MidiFileReader#getSequence(java.io.InputStream) + */ + public Sequence getSequence(InputStream is) throws InvalidMidiDataException, + IOException + { + MidiDataInputStream din = new MidiDataInputStream(is); + ExtendedMidiFileFormat mff = (ExtendedMidiFileFormat) getMidiFileFormat(din); + + Sequence seq = new Sequence(mff.getDivisionType(), mff.getResolution()); + + int ntracks = mff.getNumberTracks(); + + while (ntracks-- > 0) + { + Track track = seq.createTrack(); + int Mtrk = din.readInt(); + if (Mtrk != 0x4d54726b) + throw new InvalidMidiDataException("Invalid MIDI track header."); + int length = din.readInt(); + + int runningStatus = -1; + int click = 0; + + // Set this to true when we've hit an End of Track meta event. + boolean done = false; + + // Read all events. + while (! done) + { + MidiMessage mm; + int dtime = din.readVariableLengthInt(); + click += dtime; + + int sbyte = din.readUnsignedByte(); + + if (sbyte < 0xf0) + { + ShortMessage sm; + switch (sbyte & 0xf0) + { + case ShortMessage.NOTE_OFF: + case ShortMessage.NOTE_ON: + case ShortMessage.POLY_PRESSURE: + case ShortMessage.CONTROL_CHANGE: + case ShortMessage.PITCH_BEND: + case ShortMessage.SONG_POSITION_POINTER: + sm = new ShortMessage(); + sm.setMessage(sbyte, din.readByte(), din.readByte()); + runningStatus = sbyte; + break; + + case ShortMessage.PROGRAM_CHANGE: + case ShortMessage.CHANNEL_PRESSURE: + case ShortMessage.SONG_SELECT: + case 0xF5: // FIXME: unofficial bus select. Not in spec?? + sm = new ShortMessage(); + sm.setMessage(sbyte, din.readByte(), 0); + runningStatus = sbyte; + break; + + case ShortMessage.TUNE_REQUEST: + case ShortMessage.END_OF_EXCLUSIVE: + case ShortMessage.TIMING_CLOCK: + case ShortMessage.START: + case ShortMessage.CONTINUE: + case ShortMessage.STOP: + case ShortMessage.ACTIVE_SENSING: + case ShortMessage.SYSTEM_RESET: + sm = new ShortMessage(); + sm.setMessage(sbyte, 0, 0); + runningStatus = sbyte; + break; + + default: + if (runningStatus != - 1) + { + switch (runningStatus & 0xf0) + { + case ShortMessage.NOTE_OFF: + case ShortMessage.NOTE_ON: + case ShortMessage.POLY_PRESSURE: + case ShortMessage.CONTROL_CHANGE: + case ShortMessage.PITCH_BEND: + case ShortMessage.SONG_POSITION_POINTER: + sm = new ShortMessage(); + sm.setMessage(runningStatus, sbyte, din.readByte()); + break; + + case ShortMessage.PROGRAM_CHANGE: + case ShortMessage.CHANNEL_PRESSURE: + case ShortMessage.SONG_SELECT: + case 0xF5: // FIXME: unofficial bus select. Not in + // spec?? + sm = new ShortMessage(); + sm.setMessage(runningStatus, sbyte, 0); + continue; + + case ShortMessage.TUNE_REQUEST: + case ShortMessage.END_OF_EXCLUSIVE: + case ShortMessage.TIMING_CLOCK: + case ShortMessage.START: + case ShortMessage.CONTINUE: + case ShortMessage.STOP: + case ShortMessage.ACTIVE_SENSING: + case ShortMessage.SYSTEM_RESET: + sm = new ShortMessage(); + sm.setMessage(runningStatus, 0, 0); + continue; + + default: + throw new + InvalidMidiDataException("Invalid Short MIDI Event: " + + sbyte); + } + } + else + throw new + InvalidMidiDataException("Invalid Short MIDI Event: " + + sbyte); + } + mm = sm; + } + else if (sbyte == 0xf0 || sbyte == 0xf7) + { + // System Exclusive event + int slen = din.readVariableLengthInt(); + byte sysex[] = new byte[slen]; + din.readFully(sysex); + SysexMessage sm = new SysexMessage(); + sm.setMessage(sbyte, sysex, slen); + mm = sm; + runningStatus = - 1; + } + else if (sbyte == 0xff) + { + // Meta Message + byte mtype = din.readByte(); + int mlen = din.readVariableLengthInt(); + byte meta[] = new byte[mlen]; + din.readFully(meta); + MetaMessage metam = new MetaMessage(); + metam.setMessage(mtype, meta, mlen); + mm = metam; + + if (mtype == 0x2f) // End of Track + done = true; + + runningStatus = - 1; + } + else + { + throw new InvalidMidiDataException("Invalid status byte: " + + sbyte); + } + + track.add(new MidiEvent(mm, click)); + } + } + + return seq; + } + + /* Get the MIDI Sequence found at the given URL. + * @see javax.sound.midi.spi.MidiFileReader#getSequence(java.net.URL) + */ + public Sequence getSequence(URL url) throws InvalidMidiDataException, + IOException + { + InputStream is = url.openStream(); + try + { + return getSequence(is); + } + finally + { + is.close(); + } + } + + /* Get the MIDI Sequence found in the given file. + * @see javax.sound.midi.spi.MidiFileReader#getSequence(java.io.File) + */ + public Sequence getSequence(File file) throws InvalidMidiDataException, + IOException + { + InputStream is = new FileInputStream(file); + try + { + return getSequence(is); + } + finally + { + is.close(); + } + } +} diff --git a/libjava/classpath/gnu/javax/sound/midi/file/MidiFileWriter.java b/libjava/classpath/gnu/javax/sound/midi/file/MidiFileWriter.java new file mode 100644 index 000000000..5170fc1e7 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/midi/file/MidiFileWriter.java @@ -0,0 +1,197 @@ +/* MidiFileWriter.java -- Write MIDI files. + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.sound.midi.file; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import javax.sound.midi.MetaMessage; +import javax.sound.midi.MidiEvent; +import javax.sound.midi.Sequence; +import javax.sound.midi.Track; + +/** + * A MIDI file writer. + * + * This code writes MIDI file types 0 and 1. + * + * There are many decent documents on the web describing the MIDI file + * format. I didn't bother looking for the official document. If it + * exists, I'm not even sure if it is freely available. We should + * update this comment if we find out anything helpful here. + * + * @author Anthony Green (green@redhat.com) + * + */ +public class MidiFileWriter + extends javax.sound.midi.spi.MidiFileWriter +{ + /* Return an array indicating which midi file types are supported. + * @see javax.sound.midi.spi.MidiFileWriter#getMidiFileTypes() + */ + public int[] getMidiFileTypes() + { + return new int[]{0, 1}; + } + + /* Return an array indicating which midi file types are supported + * for a given Sequence. + * @see javax.sound.midi.spi.MidiFileWriter#getMidiFileTypes(javax.sound.midi.Sequence) + */ + public int[] getMidiFileTypes(Sequence sequence) + { + if (sequence.getTracks().length == 1) + return new int[]{0}; + else + return new int[]{1}; + } + + /* Write a sequence to an output stream in standard midi format. + * @see javax.sound.midi.spi.MidiFileWriter#write(javax.sound.midi.Sequence, int, java.io.OutputStream) + */ + public int write(Sequence in, int fileType, OutputStream out) + throws IOException + { + MidiDataOutputStream dos = new MidiDataOutputStream (out); + Track[] tracks = in.getTracks(); + dos.writeInt(0x4d546864); // MThd + dos.writeInt(6); + dos.writeShort(fileType); + dos.writeShort(tracks.length); + float divisionType = in.getDivisionType(); + int resolution = in.getResolution(); + // FIXME: division computation is incomplete. + int division = 0; + if (divisionType == Sequence.PPQ) + division = resolution & 0x7fff; + dos.writeShort(division); + int length = 14; + for (int i = 0; i < tracks.length; i++) + length += writeTrack(tracks[i], dos); + return length; + } + + /** + * Compute the length of a track as it will be written to the + * output stream. + * + * @param track the track to measure + * @param dos a MidiDataOutputStream used for helper method + * @return the length of the track + */ + private int computeTrackLength(Track track, MidiDataOutputStream dos) + { + int count = 0, length = 0, i = 0, eventCount = track.size(); + long ptick = 0; + while (i < eventCount) + { + MidiEvent me = track.get(i); + long tick = me.getTick(); + length += dos.variableLengthIntLength((int) (tick - ptick)); + ptick = tick; + length += me.getMessage().getLength(); + i++; + } + return length; + } + + /** + * Write a track to an output stream. + * + * @param track the track to write + * @param dos a MidiDataOutputStream to write to + * @return the number of bytes written + */ + private int writeTrack(Track track, MidiDataOutputStream dos) + throws IOException + { + int i = 0, elength = track.size(), trackLength; + MidiEvent pme = null; + dos.writeInt(0x4d54726b); // "MTrk" + trackLength = computeTrackLength(track, dos); + dos.writeInt(trackLength); + while (i < elength) + { + MidiEvent me = track.get(i); + int dtime = 0; + if (pme != null) + dtime = (int) (me.getTick() - pme.getTick()); + dos.writeVariableLengthInt(dtime); + // FIXME: use running status byte + byte msg[] = me.getMessage().getMessage(); + dos.write(msg); + pme = me; + i++; + } + + // We're done if the last event was an End of Track meta message. + if (pme != null && (pme.getMessage() instanceof MetaMessage)) + { + MetaMessage mm = (MetaMessage) pme.getMessage(); + if (mm.getType() == 0x2f) // End of Track message + return trackLength + 8; + } + + // Write End of Track meta message + dos.writeVariableLengthInt(0); // Delta time of 0 + dos.writeByte(0xff); // Meta Message + dos.writeByte(0x2f); // End of Track message + dos.writeVariableLengthInt(0); // Length of 0 + + return trackLength + 8 + 4; + } + + /* Write a Sequence to a file. + * @see javax.sound.midi.spi.MidiFileWriter#write(javax.sound.midi.Sequence, int, java.io.File) + */ + public int write(Sequence in, int fileType, File out) throws IOException + { + OutputStream os = new FileOutputStream(out); + try + { + return write(in, fileType, os); + } + finally + { + os.close(); + } + } + +} diff --git a/libjava/classpath/gnu/javax/sound/sampled/AU/AUReader.java b/libjava/classpath/gnu/javax/sound/sampled/AU/AUReader.java new file mode 100644 index 000000000..fe0df6eb1 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/sampled/AU/AUReader.java @@ -0,0 +1,210 @@ +/* AUReader.java -- Read AU files. + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.sound.sampled.AU; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.UnsupportedAudioFileException; +import javax.sound.sampled.spi.AudioFileReader; +import java.io.File; +import java.io.IOException; +import java.io.BufferedInputStream; +import java.io.InputStream; +import java.io.FileInputStream; +import java.net.URL; +import java.nio.ByteBuffer; + +public class AUReader extends AudioFileReader +{ + private static class AUHeader + { + // Magic number identifying the file. '.snd' + private static final int MAGIC = 0x2e736e64; + + public static final int SIZE = 24; // size of the header + + // Encoding types + public static final int ULAW = 1; // 8-bit u-law + public static final int PCM8 = 2; // 8-bit PCM + public static final int PCM16 = 3; // 16-bit PCM + public static final int PCM24 = 4; // 24-bit PCM + public static final int PCM32 = 5; // 32-bit PCM + public static final int IEEE32 = 6; // 32-bit IEEE f.p. + public static final int IEEE64 = 7; // 64-bit IEEE f.p. + public static final int G721 = 23; + public static final int G722 = 24; + public static final int G723 = 25; + public static final int G723_5BIT = 26; + public static final int ALAW = 27; // 8-bit a-law + + // Header data. + public int headerSize; + public int fileSize; // this value may not be set. + public int encoding; + public int sampleRate; + public int channels; + public int sampleSizeInBits; + + public AUHeader(InputStream stream) + throws IOException, UnsupportedAudioFileException + { + byte[] hdr = new byte[24]; + stream.read( hdr ); + ByteBuffer buf = ByteBuffer.wrap(hdr); + + if( buf.getInt() != MAGIC ) + throw new UnsupportedAudioFileException("Not an AU format audio file."); + headerSize = buf.getInt(); + fileSize = buf.getInt(); + encoding = buf.getInt(); + sampleRate = buf.getInt(); + channels = buf.getInt(); + + switch(encoding) + { + case ULAW: + case PCM8: + case ALAW: + sampleSizeInBits = 8; + break; + case PCM16: + sampleSizeInBits = 16; + break; + case PCM24: + sampleSizeInBits = 24; + break; + case PCM32: + sampleSizeInBits = 32; + break; + default: // other types exist but are not supported. Yet. + throw new UnsupportedAudioFileException("Unsupported encoding."); + } + } + + public AudioFormat getAudioFormat() + { + AudioFormat.Encoding encType = AudioFormat.Encoding.PCM_SIGNED; + if(encoding == 1) + encType = AudioFormat.Encoding.ULAW; + if(encoding == 27) + encType = AudioFormat.Encoding.ALAW; + + return new AudioFormat(encType, + (float)sampleRate, + sampleSizeInBits, + channels, + (sampleSizeInBits >> 3) * channels, + (float)sampleRate, + true); + } + + public AudioFileFormat getAudioFileFormat() + { + return new AudioFileFormat(new AUFormatType(), + getAudioFormat(), + AudioSystem.NOT_SPECIFIED); + } + } + + public static class AUFormatType extends AudioFileFormat.Type + { + public AUFormatType() + { + super("AU", ".au"); + } + } + + public AudioFileFormat getAudioFileFormat(File file) + throws IOException, UnsupportedAudioFileException + { + return getAudioFileFormat(new FileInputStream(file)); + } + + public AudioFileFormat getAudioFileFormat(InputStream stream) + throws IOException, UnsupportedAudioFileException + { + if(!stream.markSupported()) + throw new IOException("Stream must support marking."); + + stream.mark(25); + AUHeader header = new AUHeader(stream); + stream.reset(); + + return header.getAudioFileFormat(); + } + + public AudioFileFormat getAudioFileFormat(URL url) + throws IOException, UnsupportedAudioFileException + { + return getAudioFileFormat(new BufferedInputStream(url.openStream())); + } + + public AudioInputStream getAudioInputStream(File file) + throws IOException, UnsupportedAudioFileException + { + InputStream stream = new FileInputStream(file); + long length = file.length(); + + AUHeader header = new AUHeader( stream ); + if( header.headerSize > AUHeader.SIZE ) + stream.skip(header.headerSize - AUHeader.SIZE); + + length -= header.headerSize; + + return new AudioInputStream(stream, header.getAudioFormat(), length); + } + + public AudioInputStream getAudioInputStream(InputStream stream) + throws IOException, UnsupportedAudioFileException + { + AUHeader header = new AUHeader( stream ); + if( header.headerSize > AUHeader.SIZE ) + stream.skip(header.headerSize - AUHeader.SIZE); + + return new AudioInputStream(stream, header.getAudioFormat(), + AudioSystem.NOT_SPECIFIED); + } + + public AudioInputStream getAudioInputStream(URL url) + throws IOException, UnsupportedAudioFileException + { + return getAudioInputStream(new BufferedInputStream(url.openStream())); + } +} diff --git a/libjava/classpath/gnu/javax/sound/sampled/WAV/WAVReader.java b/libjava/classpath/gnu/javax/sound/sampled/WAV/WAVReader.java new file mode 100644 index 000000000..5cd6efe5e --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/sampled/WAV/WAVReader.java @@ -0,0 +1,236 @@ +/* WAVReader.java -- Read WAV files. + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.sound.sampled.WAV; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.DataInputStream; +import java.io.FileInputStream; +import java.net.URL; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.UnsupportedAudioFileException; +import javax.sound.sampled.spi.AudioFileReader; + +/** + * A WAV file reader. + * + * This code reads WAV files. + * + * There are many decent documents on the web describing the WAV file + * format. I didn't bother looking for the official document. If it + * exists, I'm not even sure if it is freely available. We should + * update this comment if we find out anything helpful here. I used + * http://www.sonicspot.com/guide/wavefiles.html + * + * @author Anthony Green (green@redhat.com) + * + */ +public class WAVReader extends AudioFileReader +{ + private static long readUnsignedIntLE (DataInputStream is) + throws IOException + { + byte[] buf = new byte[4]; + is.readFully(buf); + return (buf[0] & 0xFF + | ((buf[1] & 0xFF) << 8) + | ((buf[2] & 0xFF) << 16) + | ((buf[3] & 0xFF) << 24)); + } + + private static short readUnsignedShortLE (DataInputStream is) + throws IOException + { + byte[] buf = new byte[2]; + is.readFully(buf); + return (short) (buf[0] & 0xFF + | ((buf[1] & 0xFF) << 8)); + } + + /* Get an AudioFileFormat from the given File. + * @see javax.sound.sampled.spi.AudioFileReader#getAudioFileFormat(java.io.File) + */ + public AudioFileFormat getAudioFileFormat(File file) + throws UnsupportedAudioFileException, IOException + { + InputStream is = new FileInputStream(file); + try + { + return getAudioFileFormat(is); + } + finally + { + is.close(); + } + } + + /* Get an AudioFileFormat from the given InputStream. + * @see javax.sound.sampled.spi.AudioFileReader#getAudioFileFormat(java.io.InputStream) + */ + public AudioFileFormat getAudioFileFormat(InputStream in) + throws UnsupportedAudioFileException, IOException + { + DataInputStream din; + + if (in instanceof DataInputStream) + din = (DataInputStream) in; + else + din = new DataInputStream(in); + + if (din.readInt() != 0x52494646) // "RIFF" + throw new UnsupportedAudioFileException("Invalid WAV chunk header."); + + // Read the length of this RIFF thing. + readUnsignedIntLE(din); + + if (din.readInt() != 0x57415645) // "WAVE" + throw new UnsupportedAudioFileException("Invalid WAV chunk header."); + + boolean foundFmt = false; + boolean foundData = false; + + short compressionCode = 0, numberChannels = 0, blockAlign = 0, bitsPerSample = 0; + long sampleRate = 0, bytesPerSecond = 0; + long chunkLength = 0; + + while (! foundData) + { + int chunkId = din.readInt(); + chunkLength = readUnsignedIntLE(din); + switch (chunkId) + { + case 0x666D7420: // "fmt " + foundFmt = true; + compressionCode = readUnsignedShortLE(din); + numberChannels = readUnsignedShortLE(din); + sampleRate = readUnsignedIntLE(din); + bytesPerSecond = readUnsignedIntLE(din); + blockAlign = readUnsignedShortLE(din); + bitsPerSample = readUnsignedShortLE(din); + din.skip(chunkLength - 16); + break; + case 0x66616374: // "fact" + // FIXME: hold compression format dependent data. + din.skip(chunkLength); + break; + case 0x64617461: // "data" + if (! foundFmt) + throw new UnsupportedAudioFileException("This implementation requires WAV fmt chunks precede data chunks."); + foundData = true; + break; + default: + // Unrecognized chunk. Skip it. + din.skip(chunkLength); + } + } + + AudioFormat.Encoding encoding; + + switch (compressionCode) + { + case 1: // PCM/uncompressed + if (bitsPerSample <= 8) + encoding = AudioFormat.Encoding.PCM_UNSIGNED; + else + encoding = AudioFormat.Encoding.PCM_SIGNED; + break; + + default: + throw new UnsupportedAudioFileException("Unrecognized WAV compression code: 0x" + + Integer.toHexString(compressionCode)); + } + + return new AudioFileFormat (AudioFileFormat.Type.WAVE, + new AudioFormat(encoding, + (float) sampleRate, + bitsPerSample, + numberChannels, + ((bitsPerSample + 7) / 8) * numberChannels, + (float) bytesPerSecond, false), + (int) chunkLength); + } + + /* Get an AudioFileFormat from the given URL. + * @see javax.sound.sampled.spi.AudioFileReader#getAudioFileFormat(java.net.URL) + */ + public AudioFileFormat getAudioFileFormat(URL url) + throws UnsupportedAudioFileException, IOException + { + InputStream is = url.openStream(); + try + { + return getAudioFileFormat(is); + } + finally + { + is.close(); + } + } + + /* Get an AudioInputStream from the given File. + * @see javax.sound.sampled.spi.AudioFileReader#getAudioInputStream(java.io.File) + */ + public AudioInputStream getAudioInputStream(File file) + throws UnsupportedAudioFileException, IOException + { + return getAudioInputStream(new FileInputStream(file)); + } + + /* Get an AudioInputStream from the given InputStream. + * @see javax.sound.sampled.spi.AudioFileReader#getAudioInputStream(java.io.InputStream) + */ + public AudioInputStream getAudioInputStream(InputStream stream) + throws UnsupportedAudioFileException, IOException + { + AudioFileFormat aff = getAudioFileFormat(stream); + return new AudioInputStream(stream, aff.getFormat(), (long) aff.getFrameLength()); + } + + /* Get an AudioInputStream from the given URL. + * @see javax.sound.sampled.spi.AudioFileReader#getAudioInputStream(java.net.URL) + */ + public AudioInputStream getAudioInputStream(URL url) + throws UnsupportedAudioFileException, IOException + { + return getAudioInputStream(url.openStream()); + } +} diff --git a/libjava/classpath/gnu/javax/sound/sampled/gstreamer/GStreamerMixer.java b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/GStreamerMixer.java new file mode 100644 index 000000000..1910ea655 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/GStreamerMixer.java @@ -0,0 +1,248 @@ +/* GStreamerMixer.java -- Mixer implementation. + Copyright (C) 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.sound.sampled.gstreamer; + +import gnu.javax.sound.sampled.gstreamer.lines.GstSourceDataLine; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.Control; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.Line; +import javax.sound.sampled.LineListener; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.Mixer; +import javax.sound.sampled.SourceDataLine; +import javax.sound.sampled.Control.Type; + +/** + * @author Mario Torre + */ +public class GStreamerMixer + implements Mixer +{ + public static class GstInfo extends Info + { + /* Mixer Properties */ + + /** Name */ + private static final String name = "Classpath GStreamer Sound Audio Engine"; + + /** Vendor */ + private static final String vendor = "GNU Classpath"; + + /** Description */ + private static final String desc = "GStreamer-based software mixer"; + + /** Version */ + private static final String vers = "0.0.1"; + + protected GstInfo() + { + super(name, vendor, desc, vers); + } + } + + public static final String GST_BACKEND = GstInfo.name; + public static final String GST_DECODER = "decoder"; + public static final String GST_TYPE_NAME = "type"; + public static final String GST_FILE_EXTENSION = "ext"; + + /** Mixer Info */ + private static final Mixer.Info INFO = new GStreamerMixer.GstInfo(); + + public Line getLine(Line.Info info) + throws LineUnavailableException + { + // get all the lines formats supported by this mixer and + // and see if there is one matching the given line + // if the format comes from the gstreamer backend + // gstreamer will be able to deal with it + Class clazz = info.getLineClass(); + DataLine.Info _info = (DataLine.Info) info; + + if (clazz == SourceDataLine.class) + { + for (AudioFormat format : _info.getFormats()) + { + // see if we are a gstreamer child :) + if (format.properties().containsKey(GST_BACKEND)); + { + // we got it + return new GstSourceDataLine(format); + } + } + } + + // TODO: we also support basic PCM + + throw new LineUnavailableException("Cannot open a line"); + } + + public int getMaxLines(Line.Info info) + { + // TODO + return 1; + } + + public Info getMixerInfo() + { + return INFO; + } + + public javax.sound.sampled.Line.Info[] getSourceLineInfo() + { + // TODO Auto-generated method stub + return null; + } + + public Line.Info[] getSourceLineInfo(Line.Info info) + { + // TODO Auto-generated method stub + return null; + } + + public Line[] getSourceLines() + { + // TODO Auto-generated method stub + return null; + } + + public javax.sound.sampled.Line.Info[] getTargetLineInfo() + { + // TODO Auto-generated method stub + return null; + } + + public Line.Info[] getTargetLineInfo(Line.Info info) + { + // TODO Auto-generated method stub + return null; + } + + public Line[] getTargetLines() + { + // TODO Auto-generated method stub + return null; + } + + public boolean isLineSupported(Line.Info info) + { + // We support any kind of mixer that comes + // from our gstreamer backend. + // In addition, we support PCM based audio streams for + // direct playback. + if (info instanceof DataLine.Info) + { + DataLine.Info _dinfo = (DataLine.Info) info; + _dinfo.getFormats(); + } + + return true; + } + + public boolean isSynchronizationSupported(Line[] lines, boolean sync) + { + // TODO Auto-generated method stub + return false; + } + + public void synchronize(Line[] lines, boolean sync) + { + // TODO Auto-generated method stub + + } + + public void unsynchronize(Line[] lines) + { + // TODO Auto-generated method stub + + } + + public void addLineListener(LineListener listener) + { + // TODO Auto-generated method stub + + } + + public void close() + { + // TODO Auto-generated method stub + + } + + public Control getControl(Type what) + { + // TODO Auto-generated method stub + return null; + } + + public Control[] getControls() + { + // TODO Auto-generated method stub + return null; + } + + public javax.sound.sampled.Line.Info getLineInfo() + { + // TODO Auto-generated method stub + return null; + } + + public boolean isControlSupported(Type what) + { + // TODO Auto-generated method stub + return false; + } + + public boolean isOpen() + { + // TODO Auto-generated method stub + return false; + } + + public void open() throws LineUnavailableException + { + // TODO Auto-generated method stub + + } + + public void removeLineListener(LineListener listener) + { + // TODO Auto-generated method stub + } +} diff --git a/libjava/classpath/gnu/javax/sound/sampled/gstreamer/GStreamerMixerProvider.java b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/GStreamerMixerProvider.java new file mode 100644 index 000000000..6a0d7faa7 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/GStreamerMixerProvider.java @@ -0,0 +1,71 @@ +/*GStreamerMixerProvider -- GNU Classpath GStreamer Mixer provider. + Copyright (C) 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.sound.sampled.gstreamer; + +import javax.sound.sampled.Mixer; +import javax.sound.sampled.Mixer.Info; +import javax.sound.sampled.spi.MixerProvider; + +/** + * Concrete provider class for GStreamerMixer. + * + * @author Mario Torre + */ +public class GStreamerMixerProvider + extends MixerProvider +{ + private static final GStreamerMixer mixer = new GStreamerMixer(); + + @Override + public Mixer getMixer(Info info) + { + if (info.equals(mixer.getMixerInfo())) + return mixer; + + throw new + IllegalArgumentException("This provider cannot handle a mixer or type: " + + info.getName()); + } + + @Override + public Info[] getMixerInfo() + { + Info[] info = { mixer.getMixerInfo() }; + return info; + } +} diff --git a/libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReader.java b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReader.java new file mode 100644 index 000000000..26fb12b09 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReader.java @@ -0,0 +1,185 @@ +/*GstAudioFileReader -- GNU Classpath GStreamer AudioFileReader. + Copyright (C) 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.sound.sampled.gstreamer.io; + +import gnu.java.lang.CPStringBuilder; + +import gnu.javax.sound.sampled.gstreamer.GStreamerMixer; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.UnsupportedAudioFileException; +import javax.sound.sampled.spi.AudioFileReader; + +/** + * An implementation of a general AudioFileReader. Uses GStreamer to + * parse and retrieve informations about the file passed as input. + * + * @author Mario Torre + */ +public class GstAudioFileReader + extends AudioFileReader +{ + @Override + public AudioFileFormat getAudioFileFormat(File file) + throws UnsupportedAudioFileException, IOException + { + CPStringBuilder name = new CPStringBuilder(file.getName()); + String _name = name.substring(name.lastIndexOf(".") + 1); + + return getAudioFileFormat( + new BufferedInputStream(new FileInputStream(file)), _name); + } + + @Override + public AudioFileFormat getAudioFileFormat(InputStream is) + throws UnsupportedAudioFileException, IOException + { + return getAudioFileFormat(is, null); + } + + private AudioFileFormat getAudioFileFormat(InputStream is, String extension) + throws UnsupportedAudioFileException + { + AudioFormat format = null; + try + { + format = GstAudioFileReaderNativePeer.getAudioFormat(is); + } + catch (Exception e) + { + UnsupportedAudioFileException ex = + new UnsupportedAudioFileException("Unsupported encoding."); + + ex.initCause(ex.getCause()); + throw ex; + } + + if (format == null) + throw new UnsupportedAudioFileException("Unsupported encoding."); + + String name = format.getProperty(GStreamerMixer.GST_DECODER).toString(); + + if (extension == null) + { + extension = + format.getProperty(GStreamerMixer.GST_FILE_EXTENSION).toString(); + } + + AudioFileFormat.Type type = + new AudioFileFormat.Type(name, extension); + + // TODO: we should calculate this in some way. We don't need it, but + // application may want to use this data. + return new AudioFileFormat(type, format, AudioSystem.NOT_SPECIFIED); + } + + @Override + public AudioFileFormat getAudioFileFormat(URL url) + throws UnsupportedAudioFileException, IOException + { + return getAudioFileFormat(new BufferedInputStream(url.openStream())); + } + + @Override + public AudioInputStream getAudioInputStream(File file) + throws UnsupportedAudioFileException, IOException + { + InputStream stream = new FileInputStream(file); + long length = file.length(); + + AudioFormat format = null; + + try + { + format = GstAudioFileReaderNativePeer.getAudioFormat(file); + } + catch (Exception e) + { + UnsupportedAudioFileException ex = + new UnsupportedAudioFileException("Unsupported encoding."); + + ex.initCause(ex.getCause()); + throw ex; + } + + // get the header size + if (format == null) + throw new UnsupportedAudioFileException("Unsupported encoding."); + + return new AudioInputStream(stream, format, length); + } + + @Override + public AudioInputStream getAudioInputStream(InputStream is) + throws UnsupportedAudioFileException, IOException + { + AudioFormat format = null; + + try + { + format = GstAudioFileReaderNativePeer.getAudioFormat(is); + } + catch (Exception e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + // get the header size + if (format == null) + throw new UnsupportedAudioFileException("Unsupported encoding."); + + return new AudioInputStream(is, format, AudioSystem.NOT_SPECIFIED); + } + + @Override + public AudioInputStream getAudioInputStream(URL url) + throws UnsupportedAudioFileException, IOException + { + return getAudioInputStream(new BufferedInputStream(url.openStream())); + } +} diff --git a/libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReaderNativePeer.java b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReaderNativePeer.java new file mode 100644 index 000000000..6345d7654 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReaderNativePeer.java @@ -0,0 +1,284 @@ +/*GstAudioFileReaderNativePeer -- GNU Classpath GStreamer AudioFileReader + native peer class. + Copyright (C) 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.sound.sampled.gstreamer.io; + +import gnu.classpath.Pointer; +import gnu.javax.sound.sampled.gstreamer.GStreamerMixer; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.AudioFormat.Encoding; + +/** + * GStreamer native peer for GstAudioFileReader. + * + * @author Mario Torre + */ +final class GstAudioFileReaderNativePeer +{ + private static final String GST_ENCODING = "GStreamer Generic Audio Reader"; + + private static class GstHeader + { + /* + * NOTE: these properties are accessed by the native code, be careful + * if you change them. + * Not all the fields are necessarily set. + * + */ + public String file = null; + + public String suffix = null; + + public String name = null; + + public String mimetype = null; + + public String endianness = null; + + public String channels = null; + + public String rate = null; + + public String width = null; + + public String depth = null; + + public String isSigned = null; + + public String layer = null; + + public String bitrate = null; + + public String framed = null; + + public String type = null; + } + + public static AudioFormat getAudioFormat(File file) throws Exception + { + GstHeader header = new GstHeader(); + header.file = file.getAbsolutePath(); + + if (!gstreamer_get_audio_format_file(header)) + return null; + + return getAudioFormat(header); + } + + public static AudioFormat getAudioFormat(InputStream is) throws Exception + { + return getAudioFormat(is, new GstHeader()); + } + + public static AudioFormat getAudioFormat(URL url) throws Exception + { + GstHeader header = new GstHeader(); + header.file = url.toExternalForm(); + + return getAudioFormat(url.openStream(), header); + } + + private static AudioFormat getAudioFormat(InputStream is, GstHeader header) + throws Exception + { + BufferedInputStream stream = new BufferedInputStream(is); + if(!stream.markSupported()) + throw new IOException("Stream must support marking."); + + stream.mark(0); + + if (!gstreamer_get_audio_format_stream(header, new GstInputStream(stream). + getNativeClass())) + return null; + + return getAudioFormat(header); + } + + private static Encoding getEncoding(GstHeader header) + { + StringBuilder buffer = new StringBuilder(); + + if (header.name == null) + { + buffer.append(GST_ENCODING); + if (header.mimetype != null) + { + buffer.append(" "); + buffer.append(header.mimetype); + } + + header.name = buffer.toString(); + } + else + { + // strip the "decoder" word from the name, if any + // this is a bit ugly, the alternative would be to still output the + // full name of the decoder/demuxer + String lowerCase = header.name.toLowerCase(); + int index = lowerCase.indexOf("decoder"); + if (index == -1) + { + index = lowerCase.indexOf("demuxer"); + } + + if (index == -1) + index = lowerCase.length(); + + buffer.append(header.name.substring(0, index)); + + } + + return new Encoding(buffer.toString().trim()); + } + + private static AudioFormat getAudioFormat(GstHeader header) + throws Exception + { + int na = AudioSystem.NOT_SPECIFIED; + + /* we use mimetype as an header, but this could have some side effects */ + Encoding encoding = getEncoding(header); + + float sampleRate = ((header.rate != null) ? + new Float(header.rate).floatValue() : na); + + int sampleSizeInBits = ((header.depth != null) ? + new Integer(header.depth).intValue() : na); + + int channels = ((header.channels != null) ? + new Integer(header.channels).intValue() : na); + + boolean bigEndian = false; + if (header.endianness != null) + { + if (header.endianness.compareTo("4321") == 0) + bigEndian = true; + } + + String ext = null; + + int frameSize = na; + float frameRate = na; + String lowerCase = header.name.toLowerCase(); + + // FIXME: frameRate = sampleRate in these cases under all the tests so far + // but I'm not sure if this is always correct... + if (lowerCase.contains("law") || lowerCase.contains("au")) + { + frameSize = (sampleSizeInBits >> 3) * channels; + frameRate = sampleRate; + ext = "au"; + } + else if (lowerCase.contains("wav")) + { + frameSize = ((sampleSizeInBits + 7) / 8) * channels; + frameRate = sampleRate; + ext = "wav"; + } + else if (lowerCase.contains("iff")) + { + frameSize = (sampleSizeInBits * channels) / 8; + frameRate = sampleRate; + ext = "aiff"; + } + + // write all the additional properties we got to identify + // the gstreamer plugin actually used to deal with this stream + Map properties = new HashMap(); + properties.put(GStreamerMixer.GST_BACKEND, true); + properties.put(GStreamerMixer.GST_DECODER, header.name); + properties.put(GStreamerMixer.GST_TYPE_NAME, encoding.toString()); + if (ext != null) + properties.put(GStreamerMixer.GST_FILE_EXTENSION, ext); + + /* now we put in some of the additional properties if we have them */ + if (header.type != null) properties.put("type", header.type); + if (header.framed != null) properties.put("framed", header.framed); + if (header.bitrate != null) properties.put("bitrate", header.bitrate); + if (header.isSigned != null) properties.put("isSigned", header.isSigned); + if (header.depth != null) properties.put("depth", header.depth); + if (header.mimetype != null) properties.put("mimetype", header.mimetype); + + AudioFormat format = new AudioFormat(encoding, + sampleRate, + sampleSizeInBits, + channels, + frameSize, + frameRate, + bigEndian, + properties); + return format; + } + + /* ***** native methods ***** */ + + /** + * Retrieve header information about the stream being played. + */ + native static final + protected boolean gstreamer_get_audio_format_stream(GstHeader info, + Pointer pointer); + + /** + * Retrieve header information about the file being played. + */ + native static final + protected boolean gstreamer_get_audio_format_file(GstHeader info); + + /** + * Initialize the native peer and enables the object cache. + * It is meant to be used by the static initializer. + */ + native private static final void init_id_cache(); + + static + { + System.loadLibrary("gstreamerpeer"); //$NON-NLS-1$ + init_id_cache(); + } +} diff --git a/libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileWriter.java b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileWriter.java new file mode 100644 index 000000000..9b395dca2 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileWriter.java @@ -0,0 +1,80 @@ +/*GstAudioFileWriter -- GNU Classpath GStreamer AudioFileReader. + Copyright (C) 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ +package gnu.javax.sound.sampled.gstreamer.io; + +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; + +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioFileFormat.Type; +import javax.sound.sampled.spi.AudioFileWriter; + +public class GstAudioFileWriter + extends AudioFileWriter +{ + @Override + public Type[] getAudioFileTypes() + { + // TODO Auto-generated method stub + return null; + } + + @Override + public Type[] getAudioFileTypes(AudioInputStream ais) + { + // TODO Auto-generated method stub + return null; + } + + @Override + public int write(AudioInputStream ais, Type type, File out) + throws IOException + { + // TODO Auto-generated method stub + return 0; + } + + @Override + public int write(AudioInputStream ais, Type type, OutputStream os) + throws IOException + { + // TODO Auto-generated method stub + return 0; + } + +} diff --git a/libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstInputStream.java b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstInputStream.java new file mode 100644 index 000000000..56bddcaad --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstInputStream.java @@ -0,0 +1,119 @@ +/* GstInputStream.java -- Trampoline class for an InputStream, mean to be used + by native code. + Copyright (C) 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.sound.sampled.gstreamer.io; + +import gnu.classpath.Pointer; + +import java.io.IOException; +import java.io.InputStream; + +/** + * Encapsulates the functionality of an InputStream Object. + * + * This class is only meant to be used by the native code, to allow reading + * of the given InputStream as part of a the GStreamer InputStream Source + * Plugin. + * + * Note: this class will be not garbage collected as the + * native code contains strong references to internal fields. + * The native layer provides a method that can be called by the C code to + * free the resources and to let the garbage collected to handle this class + * when not needed anymore. + * + * @author Mario Torre + */ +public class GstInputStream +{ + /** The real InputStream on which to perform reading operations. */ + private InputStream istream; + + /** + * Initialized in the native code, don't change without changes + * in the native layer. + */ + private Pointer gstInputStream = null; + + public GstInputStream(InputStream istream) + { + this.istream = istream; + init_instance(); + } + + public int read(byte[] buf, int off, int len) throws IOException + { + return this.istream.read(buf, off, len); + } + + public int available() throws IOException + { + return this.istream.available(); + } + + /** + * Return a reference to the GstInputStream native class as a Pointer object. + * This method is intended as an helper accessor and the returned pointer + * needs to be casted and used in the native code only. + * + * @return Pointer to the native GstInputStream class. + */ + public Pointer getNativeClass() + { + return this.gstInputStream; + } + + /* native methods */ + + /** + * Initialize the native peer and enables the object cache. + * It is meant to be used by the class constructor. + */ + native private final void init_instance(); + + /** + * Initialize the native peer and enables the object cache. + * It is meant to be used by the static initializer. + */ + native private static final void init_id_cache(); + + static + { + System.loadLibrary("gstreamerpeer"); //$NON-NLS-1$ + init_id_cache(); + } +} diff --git a/libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstDataLine.java b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstDataLine.java new file mode 100644 index 000000000..4e8cb1bb2 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstDataLine.java @@ -0,0 +1,151 @@ +/* GstDataLine.java -- Abstract DataLine. + Copyright (C) 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.sound.sampled.gstreamer.lines; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.Control; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.LineListener; +import javax.sound.sampled.Control.Type; + +public abstract class GstDataLine + implements DataLine +{ + public static final int DEFAULT_BUFFER_SIZE = 1024; + + /** Represents if this Line is opened or not. */ + protected Boolean open = false; + + private AudioFormat format = null; + private int bufferSize = 0; + + public GstDataLine(AudioFormat format) + { + this.format = format; + this.bufferSize = DEFAULT_BUFFER_SIZE; + } + + public GstDataLine(AudioFormat format, int bufferSize) + { + this.format = format; + this.bufferSize = bufferSize; + } + + public int getBufferSize() + { + return this.bufferSize; + } + + public AudioFormat getFormat() + { + return this.format; + } + + public float getLevel() + { + // TODO Auto-generated method stub + return 0; + } + + public void addLineListener(LineListener listener) + { + // TODO Auto-generated method stub + + } + + public Control getControl(Type what) + { + // TODO Auto-generated method stub + return null; + } + + public Control[] getControls() + { + // TODO Auto-generated method stub + return null; + } + + public javax.sound.sampled.Line.Info getLineInfo() + { + // TODO Auto-generated method stub + return null; + } + + public boolean isControlSupported(Type what) + { + return false; + } + + public boolean isOpen() + { + // TODO Auto-generated method stub + return false; + } + + public void removeLineListener(LineListener listener) + { + // TODO Auto-generated method stub + + } + + /* protected methods for subclasses */ + + /** + * @param open the open to set + */ + protected void setOpen(Boolean open) + { + this.open = open; + } + + /** + * @param bufferSize the bufferSize to set + */ + protected void setBufferSize(int bufferSize) + { + this.bufferSize = bufferSize; + } + + /** + * @param format the format to set + */ + protected void setFormat(AudioFormat format) + { + this.format = format; + } +} diff --git a/libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstNativeDataLine.java b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstNativeDataLine.java new file mode 100644 index 000000000..896f0cb85 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstNativeDataLine.java @@ -0,0 +1,77 @@ +/* GstNativeDataLine.java -- SourceDataLine implementation. + Copyright (C) 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.sound.sampled.gstreamer.lines; + +import gnu.classpath.Pointer; + +import javax.sound.sampled.LineUnavailableException; + +public class GstNativeDataLine +{ + public static final GstPipeline createSourcePipeline(int bufferSize) + throws LineUnavailableException + { + GstPipeline pipeline = new GstPipeline(bufferSize); + + pipeline.createForWrite(); + + if (!setup_sink_pipeline(pipeline.getNativeClass())) + throw new LineUnavailableException("Line unavailable"); + + return pipeline; + } + + /* native methods */ + + /** + * Initialize the native peer and enables the object cache. + * It is meant to be used by the static initializer. + */ + native static final private void init_id_cache(); + + /** + * Setup a new GStreamer Pipeline + */ + native static final private boolean setup_sink_pipeline(Pointer pipeline); + + static + { + System.loadLibrary("gstreamerpeer"); //$NON-NLS-1$ + init_id_cache(); + } +} diff --git a/libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstPipeline.java b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstPipeline.java new file mode 100644 index 000000000..9280e9f15 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstPipeline.java @@ -0,0 +1,415 @@ +/* GstPipeline.java -- Represents a Gstreamer Pipeline. + Copyright (C) 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.sound.sampled.gstreamer.lines; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.prefs.Preferences; + +import javax.sound.sampled.LineUnavailableException; + +import gnu.classpath.Pointer; + +/** + * This class represent a GStreamer pipeline and is resposible to handle the + * flow of data to and from the GStreamer native backend. + * + * @author Mario Torre + */ +public class GstPipeline +{ + /* + * Implementation note: + * This class is at first a bit confusing as it serves as a gateway + * to a real filesystem named pipe. + * The pipelines is shared by the gstreamer backend and by the java code. + * If the operation we are performing is to play a given stream of bytes, + * we need to open the java side of the pipeline for writing, which is done + * in the prepareWrite method. At the same time, the native side of the code + * need to open the pipeline in read mode, to get access to the data, + * and hence, act as a source element. This is why you will see terms + * like "read" or "source" in methods that are used to write in the pipeline, + * in other words, each the native operation is the opposite of the java + * side operation. + * Opening the pipe to record audio data from the sound card works the same + * except that all the operation are inverted. + */ + + // These enums are used in the native code also, changes here must reflect + // changes in the native code. + public static enum State + { + PLAY, PAUSE, STOP, CLOSE + } + + private static final int READ = 0; + private static final int WRITE = 1; + private static final int QUEUED = 1; + + private static final String CAPACITY_KEY = "Capacity"; + + private static final Object [] lock = new Object[0]; + + /* + * Preference subsystem. We use this to store some system specific settings. + */ + protected Preferences prefs = + Preferences.userNodeForPackage(GstPipeline.class).node("GStreamer"); + + // used by the native code, stores the size of the named pipeline + // created by the operating system. + private long capacity = -1; + + /** Represents the playing state of this Line. */ + private State state = State.STOP; + + /** The name of the named pipe. */ + // Will be setup and filled in the native code. See the native library + // for details. + private String name = null; + + /** This is the named pipe that will be read by the gstreamer backend. */ + private FileOutputStream output = null; + + /** + * Defines if we are getting data from a sink pipe + * or writing to a source pipe. + */ + private boolean source = true; + + /** Indicate that we are ready to process audio data to/from the pipe. */ + private boolean ready = false; + + /** + * This is the native GStreamer Pipeline. + */ + // This field is used by the native code, so any change to it must be + // followed by similar changes in the native peer. + private Pointer pipeline = null; + + /** + * Creates a new GstPipeline with a capacity of + * {@link GstDataLine#DEFAULT_BUFFER_SIZE}. + * + * @see GstDataLine#DEFAULT_BUFFER_SIZE + */ + public GstPipeline() + { + this(GstDataLine.DEFAULT_BUFFER_SIZE); + } + + /** + * Creates a new GstPipeline with a capacity of bufferSize. + * @see GstDataLine#DEFAULT_BUFFER_SIZE + */ + public GstPipeline(int bufferSize) + { + // see if we need to detect the size of the named pipe or we can use + // an already computet default for this system. + // Note that this is very different from the bufferSize parameter, + // see below. + capacity = prefs.getLong(CAPACITY_KEY, -1); + if (capacity == -1) + { + synchronized (lock) + { + capacity = detect_pipe_size(); + } + + prefs.putLong(CAPACITY_KEY, capacity); + } + + // FIXME: bufferSize actually not used nor needed by the backend. + // Applications that expects a buffer of different size will be a + // bit disappointed by that.. + init_instance(); + + // need to remove the named pipe in case of abnormal termination + Runtime.getRuntime().addShutdownHook(new CleanPipeline()); + } + + /** + * Creates a source pipeline. A source pipeline is a pipe you send data for + * processing using the write method. + */ + public void createForWrite() throws LineUnavailableException + { + // create the named pipe + if (!create_named_pipe(this.pipeline)) + throw new LineUnavailableException("Unable to create filesystem pipe"); + + open_native_pipe(this.pipeline, READ); + prepareWrite(); + + this.source = true; + } + + /** + * @return the state + */ + public State getState() + { + return this.state; + } + + /** + * Closes this pipeline. + * Short hand for #setState(State.STOP). + */ + public void close() + { + setState(State.STOP); + } + + /** + * @param state the state to set + */ + public void setState(final State state) + { + int _state = -1; + switch (state) + { + case PLAY: + _state = 0; + break; + + case PAUSE: + _state = 1; + break; + + case STOP: case CLOSE: + _state = 2; + closePipe(); + break; + } + + if (set_state(pipeline, _state)) + GstPipeline.this.state = state; + } + + /** + * Return a reference to the GstPipeline native class as a Pointer object. + * This method is intended as an helper accessor and the returned pointer + * needs to be casted and used in the native code only. + * + * @return Pointer to the native GstPipeline class. + */ + public Pointer getNativeClass() + { + return this.pipeline; + } + + /** + * Write length bytes from the given buffer into this pipeline, + * starting at offset. + * This method block if the pipeline can't accept more data. + * + * @param buffer + * @param offset + * @param length + * @return + */ + public int write(byte[] buffer, int offset, int length) + { + if (this.state == State.STOP) + return -1; + else if (this.state == State.PAUSE) + return 0; + else if (!ready) + return -1; + + try + { + if (output != null) + { + output.write(buffer, offset, length); + return length; + } + return 0; + } + catch (Exception e) + { + /* nothing to do */ + } + + return -1; + } + + public int read(byte[] buffer, int offset, int length) + { + return 0; + } + + public int available() + { + if (this.source) + return available(this.pipeline, READ); + else + return available(this.pipeline, WRITE); + } + + /** + * Wait for remaining data to be enqueued in the pipeline. + */ + public void drain() + { + if (this.state == State.STOP) + return; + + try + { + // wait untill there is anymore data in the pipe + while (available(this.pipeline, QUEUED) > 0) + Thread.sleep(3000); + + // plus a bit to allow data to be processed + Thread.sleep(1000); + } + catch (InterruptedException e) + { + /* nothing to do*/ + } + } + + /** + * Flush all the data currently waiting to be processed. + */ + public void flush() + { + try + { + if (source) + this.output.flush(); + } + catch (IOException e) + { + /* nothing */ + } + } + + private void closePipe() + { + try + { + GstPipeline.this.flush(); + if (source) + GstPipeline.this.output.close(); + } + catch (IOException e) + { + /* nothing to do */ + } + } + + private void prepareWrite() + { + try + { + // if this is not completed for some reason, we will catch + // in the write method. As this call can block, we assume we will + // succeed and that the dataline can get data. + GstPipeline.this.ready = true; + GstPipeline.this.output = new FileOutputStream(name); + } + catch (Exception e) + { + GstPipeline.this.ready = false; + } + } + + /* ***** native ***** */ + + /** + * Initialize the native peer and enables the object cache. + * It is meant to be used by the static initializer. + */ + native private static final void init_id_cache(); + + /** + * Set the playing state of this pipeline. + */ + native private static final boolean set_state(Pointer pipeline, int state); + + /** + * Get the number of bytes currently available for reading or writing + * from the pipeline. + */ + native private static final int available(Pointer pipeline, int mode); + + /** + * Open the native pipeline with the given mode. + */ + native private static final void open_native_pipe(Pointer jpipeline, + int mode); + + /** + * Close the native pipeline. + */ + native private static final void close_native_pipe(Pointer jpipeline); + + /** + * Initialize the native peer and enables the object cache. + * It is meant to be used by the class constructor. + */ + native private final void init_instance(); + + /** + * Crates the named pipe used to pass data between the application code + * and gstreamer. + */ + native private final boolean create_named_pipe(Pointer jpipeline); + + /** + * Detect and return the size of the filesystem named pipe. + */ + native private final long detect_pipe_size(); + + private class CleanPipeline extends Thread + { + public void run() + { + GstPipeline.close_native_pipe(GstPipeline.this.pipeline); + } + } + + static + { + System.loadLibrary("gstreamerpeer"); //$NON-NLS-1$ + init_id_cache(); + } +} diff --git a/libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstSourceDataLine.java b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstSourceDataLine.java new file mode 100644 index 000000000..2bc2de454 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstSourceDataLine.java @@ -0,0 +1,153 @@ +/* GstSourceDataLine.java -- SourceDataLine implementation. + Copyright (C) 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.sound.sampled.gstreamer.lines; + +import gnu.javax.sound.AudioSecurityManager; +import gnu.javax.sound.sampled.gstreamer.lines.GstPipeline.State; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.SourceDataLine; + +import static gnu.javax.sound.AudioSecurityManager.Permission; + +public class GstSourceDataLine + extends GstDataLine implements SourceDataLine +{ + private GstPipeline pipeline = null; + private boolean open = false; + + public GstSourceDataLine(AudioFormat format) + { + super(format); + } + + public void open() throws LineUnavailableException + { + AudioSecurityManager.checkPermissions(Permission.PLAY); + + if (open) + throw new IllegalStateException("Line already opened"); + + // create the pipeline + pipeline = GstNativeDataLine.createSourcePipeline(getBufferSize()); + + this.open = true; + } + + public void open(AudioFormat fmt) throws LineUnavailableException + { + AudioSecurityManager.checkPermissions(Permission.PLAY); + + setFormat(fmt); + this.open(); + } + + public void open(AudioFormat fmt, int size) throws LineUnavailableException + { + AudioSecurityManager.checkPermissions(Permission.PLAY); + + setBufferSize(size); + this.open(fmt); + } + + public int write(byte[] buf, int offset, int length) + { + return this.pipeline.write(buf, offset, length); + } + + public int available() + { + return this.pipeline.available(); + } + + public void drain() + { + this.pipeline.drain(); + } + + public void flush() + { + this.pipeline.flush(); + } + + public int getFramePosition() + { + System.out.println("getFramePosition -: IMPLEMENT ME!!"); + return 0; + } + + public long getLongFramePosition() + { + System.out.println("getLongFramePosition -: IMPLEMENT ME!!"); + return 0; + } + + public long getMicrosecondPosition() + { + System.out.println("getMicrosecondPosition -: IMPLEMENT ME!!"); + return 0; + } + + public boolean isActive() + { + State state = pipeline.getState(); + return (state == State.PLAY || state == State.PAUSE); + } + + public void start() + { + pipeline.setState(State.PLAY); + } + + public void stop() + { + pipeline.setState(State.PAUSE); + } + + public void close() + { + pipeline.close(); + this.open = false; + } + + public boolean isRunning() + { + return (pipeline.getState() == State.PLAY); + } +} diff --git a/libjava/classpath/gnu/javax/swing/plaf/gnu/GNULookAndFeel.java b/libjava/classpath/gnu/javax/swing/plaf/gnu/GNULookAndFeel.java new file mode 100644 index 000000000..75ba45506 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/plaf/gnu/GNULookAndFeel.java @@ -0,0 +1,266 @@ +/* GNULookAndFeel.java -- An example of using the javax.swing UI. + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath examples. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. +*/ + +package gnu.javax.swing.plaf.gnu; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; + +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JCheckBox; +import javax.swing.JRadioButton; +import javax.swing.UIDefaults; +import javax.swing.plaf.ColorUIResource; +import javax.swing.plaf.IconUIResource; +import javax.swing.plaf.basic.BasicLookAndFeel; + +public class GNULookAndFeel extends BasicLookAndFeel +{ + + static Color blueGray = new Color(0xdc, 0xda, 0xd5); + + public boolean isNativeLookAndFeel() { return true; } + public boolean isSupportedLookAndFeel() { return true; } + public String getDescription() { return "GNU Look and Feel"; } + public String getID() { return "GNULookAndFeel"; } + public String getName() { return "GNU"; } + + static UIDefaults LAF_defaults; + + private final static String iconspath = "/gnu/javax/swing/plaf/gtk/icons/"; + + public UIDefaults getDefaults() + { + if (LAF_defaults == null) + { + LAF_defaults = super.getDefaults(); + Object[] myDefaults = new Object[] { + "Button.background", new ColorUIResource(blueGray), + "CheckBox.background", new ColorUIResource(blueGray), + "CheckBoxMenuItem.background", new ColorUIResource(blueGray), + "ToolBar.background", new ColorUIResource(blueGray), + "Panel.background", new ColorUIResource(blueGray), + "Slider.background", new ColorUIResource(blueGray), + "OptionPane.background", new ColorUIResource(blueGray), + "ProgressBar.background", new ColorUIResource(blueGray), + "TabbedPane.background", new ColorUIResource(blueGray), + "Label.background", new ColorUIResource(blueGray), + "Menu.background", new ColorUIResource(blueGray), + "MenuBar.background", new ColorUIResource(blueGray), + "MenuItem.background", new ColorUIResource(blueGray), + "ScrollBar.background", new ColorUIResource(blueGray), + "CheckBox.icon", new CheckBoxIcon(), + "RadioButton.icon", new RadioButtonIcon(), + "Tree.hash", new ColorUIResource(Color.black), + + "Tree.closedIcon", + new IconUIResource(new ImageIcon + (getClass().getResource + (iconspath + "TreeClosed.png"))), + "Tree.leafIcon", + new IconUIResource(new ImageIcon + (getClass().getResource + (iconspath + "TreeLeaf.png"))), + "Tree.openIcon", + new IconUIResource(new ImageIcon + (getClass().getResource + (iconspath + "TreeOpen.png"))), + }; + LAF_defaults.putDefaults(myDefaults); + } + return LAF_defaults; + } + + /** + * The icon used for CheckBoxes in the BasicLookAndFeel. This is an empty + * icon with a size of 13x13 pixels. + */ + static class CheckBoxIcon + implements Icon + { + /** + * Returns the height of the icon. The BasicLookAndFeel CheckBox icon + * has a height of 13 pixels. + * + * @return the height of the icon + */ + public int getIconHeight() + { + return 13; + } + + /** + * Returns the width of the icon. The BasicLookAndFeel CheckBox icon + * has a width of 13 pixels. + * + * @return the height of the icon + */ + public int getIconWidth() + { + return 13; + } + + /** + * Paints the icon. The BasicLookAndFeel CheckBox icon is empty and does + * not need to be painted. + * + * @param c the component to be painted + * @param g the Graphics context to be painted with + * @param x the x position of the icon + * @param y the y position of the icon + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + Color save = g.getColor(); + g.setColor(c.getForeground()); + g.drawRect(x, y, getIconWidth(), getIconHeight()); + + JCheckBox item = (JCheckBox) c; + if (item.isSelected()) + { + g.drawLine(3 + x, 5 + y, 3 + x, 9 + y); + g.drawLine(4 + x, 5 + y, 4 + x, 9 + y); + g.drawLine(5 + x, 7 + y, 9 + x, 3 + y); + g.drawLine(5 + x, 8 + y, 9 + x, 4 + y); + } + + g.setColor(save); + } + } + + /** + * The icon used for RadioButtons in the GNULookAndFeel. This is an empty + * icon with a size of 13x13 pixels. + */ + static class RadioButtonIcon + implements Icon + { + /** + * Returns the height of the icon. The GNULookAndFeel RadioButton icon + * has a height of 13 pixels. + * + * @return the height of the icon + */ + public int getIconHeight() + { + return 13; + } + + /** + * Returns the width of the icon. The GNULookAndFeel RadioButton icon + * has a width of 13 pixels. + * + * @return the height of the icon + */ + public int getIconWidth() + { + return 13; + } + + /** + * Paints the icon. The GNULookAndFeel RadioButton icon is empty and does + * not need to be painted. + * + * @param c the component to be painted + * @param g the Graphics context to be painted with + * @param x the x position of the icon + * @param y the y position of the icon + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + Color savedColor = g.getColor(); + JRadioButton b = (JRadioButton) c; + + // draw outer circle + if (b.isEnabled()) + g.setColor(Color.GRAY); + else + g.setColor(Color.GRAY); + g.drawLine(x + 2, y + 1, x + 3, y + 1); + g.drawLine(x + 4, y, x + 7, y); + g.drawLine(x + 8, y + 1, x + 9, y + 1); + g.drawLine(x + 10, y + 2, x + 10, y + 3); + g.drawLine(x + 11, y + 4, x + 11, y + 7); + g.drawLine(x + 10, y + 8, x + 10, y + 9); + g.drawLine(x + 8, y + 10, x + 9, y + 10); + g.drawLine(x + 4, y + 11, x + 7, y + 11); + g.drawLine(x + 2, y + 10, x + 3, y + 10); + g.drawLine(x + 1, y + 9, x + 1, y + 8); + g.drawLine(x, y + 7, x, y + 4); + g.drawLine(x + 1, y + 2, x + 1, y + 3); + + if (b.getModel().isArmed()) + { + g.setColor(Color.GRAY); + g.drawLine(x + 4, y + 1, x + 7, y + 1); + g.drawLine(x + 4, y + 10, x + 7, y + 10); + g.drawLine(x + 1, y + 4, x + 1, y + 7); + g.drawLine(x + 10, y + 4, x + 10, y + 7); + g.fillRect(x + 2, y + 2, 8, 8); + } + else + { + // only draw inner highlight if not filled + if (b.isEnabled()) + { + g.setColor(Color.WHITE); + + g.drawLine(x + 2, y + 8, x + 2, y + 9); + g.drawLine(x + 1, y + 4, x + 1, y + 7); + g.drawLine(x + 2, y + 2, x + 2, y + 3); + g.drawLine(x + 3, y + 2, x + 3, y + 2); + g.drawLine(x + 4, y + 1, x + 7, y + 1); + g.drawLine(x + 8, y + 2, x + 9, y + 2); + } + } + + // draw outer highlight + if (b.isEnabled()) + { + g.setColor(Color.WHITE); + + // outer + g.drawLine(x + 10, y + 1, x + 10, y + 1); + g.drawLine(x + 11, y + 2, x + 11, y + 3); + g.drawLine(x + 12, y + 4, x + 12, y + 7); + g.drawLine(x + 11, y + 8, x + 11, y + 9); + g.drawLine(x + 10, y + 10, x + 10, y + 10); + g.drawLine(x + 8, y + 11, x + 9, y + 11); + g.drawLine(x + 4, y + 12, x + 7, y + 12); + g.drawLine(x + 2, y + 11, x + 3, y + 11); + } + + if (b.isSelected()) + { + if (b.isEnabled()) + g.setColor(Color.BLACK); + else + g.setColor(Color.GRAY); + g.drawLine(x + 4, y + 3, x + 7, y + 3); + g.fillRect(x + 3, y + 4, 6, 4); + g.drawLine(x + 4, y + 8, x + 7, y + 8); + } + g.setColor(savedColor); + } + } +} diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Error.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Error.png new file mode 100644 index 000000000..9d6f12278 Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Error.png differ diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Inform.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Inform.png new file mode 100644 index 000000000..89931d54d Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Inform.png differ diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/JavaCup.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/JavaCup.png new file mode 100644 index 000000000..d2cff6258 Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/JavaCup.png differ diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/JavaCupLarge.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/JavaCupLarge.png new file mode 100644 index 000000000..6a4f7923a Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/JavaCupLarge.png differ diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Question.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Question.png new file mode 100644 index 000000000..89931d54d Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Question.png differ diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/README b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/README new file mode 100644 index 000000000..755f31820 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/README @@ -0,0 +1,20 @@ +Images required by Basic Look and Feel + +Information based on images from Swing 1.1.1b2 +JavaCup.gif - a picture of the steaming cup of Java - 16x16 - 3 colors + +TreeOpen.gif - a picture of an open file folder - 16x13 - 8 colors +TreeClosed.gif - a picture of a closed file folder - 16x13 - 7 colors +TreeLeaf.gif - a picture of a small circle with points in four + directions - 16x13 - 2 colors + +Information on images used by Gtk Look and Feel, really need to work the +number of colors down I think. + +JavaCup.gif - a picture of Classpath's mascot - 16x16 - 58 colors + +TreeOpen.gif - taken from Gnome File Manager - 16x12 - 34 colors +TreeClosed.gif - taken from Gnome File Manager 14x12 - 28 colors +TreeLeaf.gif - a blank gif - 16x12 - 1 color + +Error.gif - think this will be needed later (taken from gnome) diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeClosed.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeClosed.png new file mode 100644 index 000000000..e2edbf78e Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeClosed.png differ diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeLeaf-normal.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeLeaf-normal.png new file mode 100644 index 000000000..fb8dbc982 Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeLeaf-normal.png differ diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeLeaf.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeLeaf.png new file mode 100644 index 000000000..cdf058fe6 Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeLeaf.png differ diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeOpen.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeOpen.png new file mode 100644 index 000000000..fba82587a Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeOpen.png differ diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Warn.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Warn.png new file mode 100644 index 000000000..9d6f12278 Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Warn.png differ diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/file-folders.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/file-folders.png new file mode 100644 index 000000000..e1a03d0c9 Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/file-folders.png differ diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/slider.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/slider.png new file mode 100644 index 000000000..ac429b158 Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/slider.png differ diff --git a/libjava/classpath/gnu/javax/swing/plaf/metal/CustomizableTheme.java b/libjava/classpath/gnu/javax/swing/plaf/metal/CustomizableTheme.java new file mode 100644 index 000000000..7dbf6e12a --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/plaf/metal/CustomizableTheme.java @@ -0,0 +1,218 @@ +/* CustomizableTheme.java -- A customizable metal theme + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.plaf.metal; + +import java.awt.Color; + +import javax.swing.plaf.ColorUIResource; +import javax.swing.plaf.metal.DefaultMetalTheme; + +/** + * A Metal theme that can be customized by setting the primary and secondary + * colors. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class CustomizableTheme + extends DefaultMetalTheme + implements Cloneable +{ + + /** + * The primary1 color. + */ + private ColorUIResource primary1; + + /** + * The primary2 color. + */ + private ColorUIResource primary2; + + /** + * The primary3 color. + */ + private ColorUIResource primary3; + + /** + * The secondary1 color. + */ + private ColorUIResource secondary1; + + /** + * The secondary2 color. + */ + private ColorUIResource secondary2; + + /** + * The secondary3 color. + */ + private ColorUIResource secondary3; + + /** + * Sets the primary1 color of the theme. + * + * @param c the primary1 color to set + */ + public void setPrimary1(Color c) + { + primary1 = new ColorUIResource(c); + } + + /** + * Returns the primary1 color of this theme. + * + * @return the primary1 color of this theme + */ + public ColorUIResource getPrimary1() + { + return primary1 == null ? super.getPrimary1() : primary1; + } + + + /** + * Sets the primary2 color of the theme. + * + * @param c the primary2 color to set + */ + public void setPrimary2(Color c) + { + primary2 = new ColorUIResource(c); + } + + /** + * Returns the primary2 color of this theme. + * + * @return the primary2 color of this theme + */ + public ColorUIResource getPrimary2() + { + return primary2 == null ? super.getPrimary2() : primary2; + } + + /** + * Sets the primary3 color of the theme. + * + * @param c the primary3 color to set + */ + public void setPrimary3(Color c) + { + primary3 = new ColorUIResource(c); + } + + /** + * Returns the primary3 color of this theme. + * + * @return the primary3 color of this theme + */ + public ColorUIResource getPrimary3() + { + return primary3 == null ? super.getPrimary3() : primary3; + } + + /** + * Sets the secondary1 color of the theme. + * + * @param c the secondary1 color to set + */ + public void setSecondary1(Color c) + { + secondary1 = new ColorUIResource(c); + } + + /** + * Returns the secondary1 color of this theme. + * + * @return the secondary1 color of this theme + */ + public ColorUIResource getSecondary1() + { + return secondary1 == null ? super.getSecondary1() : secondary1; + } + + /** + * Sets the secondary2 color of the theme. + * + * @param c the secondary2 color to set + */ + public void setSecondary2(Color c) + { + secondary2 = new ColorUIResource(c); + } + + /** + * Returns the secondary2 color of this theme. + * + * @return the secondary2 color of this theme + */ + public ColorUIResource getSecondary2() + { + return secondary2 == null ? super.getSecondary2() : secondary2; + } + + /** + * Sets the secondary3 color of the theme. + * + * @param c the secondary3 color to set + */ + public void setSecondary3(Color c) + { + secondary3 = new ColorUIResource(c); + } + + /** + * Returns the secondary3 color of this theme. + * + * @return the secondary3 color of this theme + */ + public ColorUIResource getSecondary3() + { + return secondary3 == null ? super.getSecondary3() : secondary3; + } + + /** + * Returns a clone of this theme. + * + * @return a clone of this theme + */ + public Object clone() + throws CloneNotSupportedException + { + return super.clone(); + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/CharacterAttributeTranslator.java b/libjava/classpath/gnu/javax/swing/text/html/CharacterAttributeTranslator.java new file mode 100644 index 000000000..d4e58eb5d --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/CharacterAttributeTranslator.java @@ -0,0 +1,192 @@ +/* CharacterAttributeTranslator.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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.swing.text.html; + +import java.awt.Color; +import java.util.HashMap; +import java.util.StringTokenizer; + +import javax.swing.text.MutableAttributeSet; +import javax.swing.text.StyleConstants; +import javax.swing.text.html.HTML.Attribute; +import javax.swing.text.html.HTML.Tag; + +/** + * This is a small utility class to translate HTML character attributes to + * Swing StyleConstants + */ +public class CharacterAttributeTranslator +{ + /** + * Maps color name to its hex encoding. + */ + private static final HashMap colorMap = new HashMap(); + static + { + colorMap.put("aqua" , "#00FFFF"); + colorMap.put("blue" , "#0000FF"); + colorMap.put("black", "#000000"); + colorMap.put("fuchsia" , "#FF00FF"); + colorMap.put("gray" , "#808080"); + colorMap.put("green" , "#008000"); + colorMap.put("lime" , "#00FF00"); + colorMap.put("maroon" , "#800000"); + colorMap.put("navy" , "#000080"); + colorMap.put("olive" , "#808000"); + colorMap.put("purple" , "#800080"); + colorMap.put("red" , "#FF0000"); + colorMap.put("silver" , "#C0C0C0"); + colorMap.put("teal" , "#008080"); + colorMap.put("white" , "#FFFFFF"); + colorMap.put("yellow" , "#FFFF00"); + } + + /** + * Convert the color string represenation into java.awt.Color. The valid + * values are like "aqua" , "#00FFFF" or "rgb(1,6,44)". + * + * @param colorName the color to convert. + * @return the matching java.awt.color + */ + public static Color getColor(String colorName) + { + colorName = colorName.toLowerCase(); + try + { + if (colorName.startsWith("rgb")) + { + // rgb(red, green, blue) notation. + StringTokenizer st = new StringTokenizer(colorName, " ,()"); + String representation = st.nextToken(); + + // Return null if the representation is not supported. + if (! representation.equals("rgb")) + return null; + int red = Integer.parseInt(st.nextToken()); + int green = Integer.parseInt(st.nextToken()); + int blue = Integer.parseInt(st.nextToken()); + + return new Color(red, green, blue); + } + else + { + String s2 = (String) colorMap.get(colorName); + if (s2 == null) + s2 = colorName; + return Color.decode(s2); + } + } + catch (Exception nex) + { + // Can be either number format exception or illegal argument + // exception. + return null; + } + } + + /** + * Translate the HTML character attribute to the Swing style constant. + * + * @param charAttr the character attributes of the html tag + * @param t the html tag itself + * @param a the attribute set where the translated attributes will be stored + * + * @return true if some attributes were translated, false otherwise. + */ + public static boolean translateTag(MutableAttributeSet charAttr, + Tag t, MutableAttributeSet a) + { + if(t == Tag.FONT) + { + Object color = a.getAttribute(Attribute.COLOR); + if(color != null) + { + Color c = getColor(color.toString()); + if( c == null ) + return false; + charAttr.addAttribute(StyleConstants.Foreground, c); + return true; + } + + if(a.getAttribute(Attribute.SIZE) != null) + { + // FIXME + // charAttr.addAttribute(StyleConstants.FontSize, + // new java.lang.Integer(72)); + return true; + } + } + + if( t == Tag.B ) + { + charAttr.addAttribute(StyleConstants.Bold, Boolean.TRUE); + return true; + } + + if( t == Tag.I ) + { + charAttr.addAttribute(StyleConstants.Italic, Boolean.TRUE); + return true; + } + + if( t == Tag.U ) + { + charAttr.addAttribute(StyleConstants.Underline, Boolean.TRUE); + return true; + } + + if( t == Tag.STRIKE ) + { + charAttr.addAttribute(StyleConstants.StrikeThrough, Boolean.TRUE); + return true; + } + + if( t == Tag.SUP ) + { + charAttr.addAttribute(StyleConstants.Superscript, Boolean.TRUE); + return true; + } + + if( t == Tag.SUB ) + { + charAttr.addAttribute(StyleConstants.Subscript, Boolean.TRUE); + return true; + } + return false; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/CombinedAttributes.java b/libjava/classpath/gnu/javax/swing/text/html/CombinedAttributes.java new file mode 100644 index 000000000..c3fe66816 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/CombinedAttributes.java @@ -0,0 +1,213 @@ +/* CombinedAttributes.java -- A two combined sets of attributes + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html; + +import java.io.Serializable; +import java.util.Enumeration; + +import javax.swing.text.AttributeSet; +import javax.swing.text.SimpleAttributeSet; + +/** + * Contains the two combined attribute sets what are searched subsequently. + * This is used to combine style sheet attributes with the HTML view attributes. + * The parent cannot be used as the view may have its own attribute hierarchy. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class CombinedAttributes implements AttributeSet, Serializable +{ + /** + * Returns the elements from both enumerations. + */ + class CombinedEnumeration implements Enumeration + { + /** + * Create a combined enumeration that enumerates over two enumerations. + * + * @param first the first enumeration to enumerate + * @param second the second enumeration to enumerate + */ + CombinedEnumeration(Enumeration first, Enumeration second) + { + a = first; + b = second; + } + + /** + * The first enumeration (elements returned first) + */ + final Enumeration a; + + /** + * The second enumeration (elements returned later) + */ + final Enumeration b; + + /** @inheritDoc */ + public boolean hasMoreElements() + { + return a.hasMoreElements() || b.hasMoreElements(); + } + + /** @inheritDoc */ + public Object nextElement() + { + return a.hasMoreElements() ? a.nextElement():b.nextElement(); + } + } + + + /** + * The first attribute set. + */ + final AttributeSet a; + + /** + * The second attribute set. + */ + final AttributeSet b; + + /** + * Create the CombinedAttributes what search in the two sets. If any of the + * two passed sets is null, another set is returned. Otherwise, the combined + * attribute set is returned. + * + * @param primary the first set (searched first) + * @param secondary the second set (searched later). + */ + public static AttributeSet combine(AttributeSet primary, + AttributeSet secondary) + { + if (primary == null) + return secondary; + else if (secondary == null) + return primary; + else + return new CombinedAttributes(primary, secondary); + } + + /** + * Create the CombinedAttributes what search in the two sets. + * + * @param primary the first set (searched first) + * @param secondary the second set (searched later). + */ + private CombinedAttributes(AttributeSet primary, AttributeSet secondary) + { + a = primary; + b = secondary; + } + + /** @inheritDoc */ + public boolean containsAttribute(Object name, Object value) + { + return a.containsAttribute(name, value) || b.containsAttribute(name, value); + } + + /** @inheritDoc */ + public boolean containsAttributes(AttributeSet attributes) + { + Enumeration names = attributes.getAttributeNames(); + Object name; + while (names.hasMoreElements()) + { + name = names.nextElement(); + if (!containsAttribute(name, attributes.getAttribute(name))) + return false; + } + return true; + } + + /** @inheritDoc */ + public AttributeSet copyAttributes() + { + SimpleAttributeSet copy = new SimpleAttributeSet(); + copy.addAttributes(a); + copy.addAttributes(b); + return copy; + } + + /** @inheritDoc */ + public Object getAttribute(Object key) + { + Object value = a.getAttribute(key); + if (value == null) + value = b.getAttribute(key); + + return value; + } + + /** @inheritDoc */ + public int getAttributeCount() + { + return a.getAttributeCount()+b.getAttributeCount(); + } + + /** @inheritDoc */ + public Enumeration getAttributeNames() + { + return new CombinedEnumeration(a.getAttributeNames(), b.getAttributeNames()); + } + + /** + * There is no one. + * + * @return null, always. + */ + public AttributeSet getResolveParent() + { + return null; + } + + /** @inheritDoc */ + public boolean isDefined(Object attrName) + { + return a.isDefined(attrName) || b.isDefined(attrName); + } + + /** @inheritDoc */ + public boolean isEqual(AttributeSet attr) + { + if (attr.getAttributeCount() == getAttributeCount()) + return containsAttributes(attr); + else + return false; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/ImageViewIconFactory.java b/libjava/classpath/gnu/javax/swing/text/html/ImageViewIconFactory.java new file mode 100644 index 000000000..ef3a1c6d1 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/ImageViewIconFactory.java @@ -0,0 +1,282 @@ +package gnu.javax.swing.text.html; + + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.io.Serializable; + +import javax.swing.Icon; +import javax.swing.plaf.metal.MetalLookAndFeel; + +/** + * Creates icons for ImageView. The icons reflect the basic ideas of the Sun's + * icons as they would be described in the text (sheet of paper with image and + * broken sheet of paper with image). They are not pixel to pixel identical and + * contain elements from the metal icon factory. + * + * @author Audrius Meskauskas (audriusa@bioinformatics.org) + */ +public class ImageViewIconFactory +{ + private static Icon noImageIcon; + + private static Icon loadingImageIcon; + + /** + * This icon reflects the general concept (broken sheet of paper with + * image), but is currently not pixel to pixel identical with the Sun's + * implementation. + */ + public static class NoImageIcon implements Icon, Serializable + { + /** + * Creates a new icon. + */ + public NoImageIcon() + { + // Nothing to do here. + } + + /** + * Returns the width of the icon, in pixels. + * + * @return The width of the icon. + */ + public int getIconWidth() + { + return 38; + } + + /** + * Returns the height of the icon, in pixels. + * + * @return The height of the icon. + */ + public int getIconHeight() + { + return 38; + } + + /** + * Paints the icon using colors from the {@link MetalLookAndFeel}. + * + * @param c + * the component (ignored). + * @param g + * the graphics device. + * @param x + * the x-coordinate for the top-left of the icon. + * @param y + * the y-coordinate for the top-left of the icon. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + // frame + Color savedColor = g.getColor(); + + g.setColor(MetalLookAndFeel.getBlack()); + + g.drawLine(x, y, x + 19, y); + + g.drawLine(x, y + 1, x, y + 5); + g.drawLine(x, y + 13, x, y + 25); + + g.drawLine(x, y + 25, x + 22, y + 25); + + g.drawLine(x + 22, y + 25, x + 22, y + 21); + g.drawLine(x + 22, y + 13, x + 22, y + 6); + + g.drawLine(x + 22, y + 6, x + 19, y); + + g.drawLine(x + 17, y + 2, x + 21, y + 6); + + g.drawLine(x + 18, y + 1, x + 19, y + 1); + + g.setColor(MetalLookAndFeel.getControlShadow()); + + g.drawLine(x + 1, y + 1, x + 17, y + 1); + + g.drawLine(x + 1, y + 1, x + 1, y + 5); + g.drawLine(x + 1, y + 13, x + 1, y + 24); + + g.drawLine(x + 1, y + 24, x + 21, y + 24); + + g.drawLine(x + 21, y + 24, x + 21, y + 21); + g.drawLine(x + 21, y + 13, x + 21, y + 7); + + g.drawLine(x + 18, y + 2, x + 20, y + 4); + + // Breaking line + + // Shadow + g.drawLine(x + 1, y + 6, x + 20, y + 13); + g.drawLine(x + 1, y + 13, x + 20, y + 20); + + // Edge + g.setColor(MetalLookAndFeel.getBlack()); + g.drawLine(x, y + 6, x + 21, y + 14); + g.drawLine(x, y + 12, x + 21, y + 20); + + // Picture + + y += 1; + x += 3; + + g.setColor(MetalLookAndFeel.getBlack()); + + // roof + g.drawLine(x + 4, y + 5, x + 8, y + 1); + g.drawLine(x + 8, y + 1, x + 15, y + 8); + + // chimney + g.drawLine(x + 11, y + 2, x + 11, y + 4); + g.drawLine(x + 12, y + 2, x + 12, y + 5); + + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + + // roof paint + int xx = x + 8; + for (int i = 0; i < 4; i++) + g.drawLine(xx - i, y + 2 + i, xx + i, y + 2 + i); + g.fillRect(x + 4, y + 6, 9, 2); + + // base of house + g.drawLine(x + 3, y + 14, x + 3, y + 18); + g.drawLine(x + 3, y + 18, x + 13, y + 18); + + g.setColor(savedColor); + } + } + + /** + * This icon reflects the general concept (sheet of paper with image), but is + * currently not pixel to pixel identical with the Sun's implementation. + */ + public static class LoadingImageIcon implements Icon, Serializable + { + + /** + * Creates a new icon. + */ + public LoadingImageIcon() + { + // Nothing to do here. + } + + /** + * Returns the width of the icon, in pixels. + * + * @return The width of the icon. + */ + public int getIconWidth() + { + return 38; + } + + /** + * Returns the height of the icon, in pixels. + * + * @return The height of the icon. + */ + public int getIconHeight() + { + return 38; + } + + /** + * Paints the icon using colors from the {@link MetalLookAndFeel}. + * + * @param c + * the component (ignored). + * @param g + * the graphics device. + * @param x + * the x-coordinate for the top-left of the icon. + * @param y + * the y-coordinate for the top-left of the icon. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + // frame + Color savedColor = g.getColor(); + + g.setColor(Color.black); + g.drawLine(x, y, x + 19, y); + g.drawLine(x, y + 1, x, y + 25); + g.drawLine(x, y + 25, x + 22, y + 25); + g.drawLine(x + 22, y + 25, x + 22, y + 6); + g.drawLine(x + 22, y + 6, x + 19, y); + + g.drawLine(x + 17, y + 2, x + 21, y + 6); + g.drawLine(x + 18, y + 1, x + 19, y + 1); + + g.setColor(new Color(204, 204, 255)); + + g.drawLine(x + 1, y + 1, x + 17, y + 1); + g.drawLine(x + 1, y + 1, x + 1, y + 24); + g.drawLine(x + 1, y + 24, x + 21, y + 24); + g.drawLine(x + 21, y + 24, x + 21, y + 7); + g.drawLine(x + 18, y + 2, x + 20, y + 4); + + // Picture (house) + + y += 3; + x += 3; + + g.setColor(MetalLookAndFeel.getBlack()); + + // roof + g.drawLine(x + 1, y + 8, x + 8, y + 1); + g.drawLine(x + 8, y + 1, x + 15, y + 8); + + // base of house + g.drawLine(x + 3, y + 6, x + 3, y + 15); + g.drawLine(x + 3, y + 15, x + 13, y + 15); + g.drawLine(x + 13, y + 6, x + 13, y + 15); + + // door frame + g.drawLine(x + 6, y + 9, x + 6, y + 15); + g.drawLine(x + 6, y + 9, x + 10, y + 9); + g.drawLine(x + 10, y + 9, x + 10, y + 15); + + // chimney + g.drawLine(x + 11, y + 2, x + 11, y + 4); + g.drawLine(x + 12, y + 2, x + 12, y + 5); + + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + + // roof paint + int xx = x + 8; + for (int i = 0; i < 4; i++) + g.drawLine(xx - i, y + 2 + i, xx + i, y + 2 + i); + g.fillRect(x + 4, y + 6, 9, 2); + + // door knob + g.drawLine(x + 9, y + 12, x + 9, y + 12); + + // house paint + g.setColor(MetalLookAndFeel.getPrimaryControl()); + g.drawLine(x + 4, y + 8, x + 12, y + 8); + g.fillRect(x + 4, y + 9, 2, 6); + g.fillRect(x + 11, y + 9, 2, 6); + + g.setColor(savedColor); + } + } + + public static Icon getNoImageIcon() + { + if (noImageIcon == null) + noImageIcon = new NoImageIcon(); + return noImageIcon; + } + + public static Icon getLoadingImageIcon() + { + if (loadingImageIcon == null) + loadingImageIcon = new LoadingImageIcon(); + return loadingImageIcon; + } + +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/BorderStyle.java b/libjava/classpath/gnu/javax/swing/text/html/css/BorderStyle.java new file mode 100644 index 000000000..3ccd38491 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/BorderStyle.java @@ -0,0 +1,64 @@ +/* BorderStyle.java -- Utility for dealing with border styles + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.css; + +/** + * Utility class for handling border styles. + */ +public class BorderStyle +{ + + /** + * Determines if a given value makes up a valid border style value. + * + * @param value the value to check + * + * @return true when this is a valid border style, + * false otherwise + */ + public static boolean isValidStyle(String value) + { + return value.equals("none") || value.equals("hidden") + || value.equals("dotted") || value.equals("dashed") + || value.equals("solid") || value.equals("double") + || value.equals("groove") || value.equals("ridge") + || value.equals("inset") || value.equals("outset"); + + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/BorderWidth.java b/libjava/classpath/gnu/javax/swing/text/html/css/BorderWidth.java new file mode 100644 index 000000000..ae64c2110 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/BorderWidth.java @@ -0,0 +1,78 @@ +/* BorderWidth.java -- A CSS metric for border widths + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.css; + +/** + * A special CSS metric for border widths. It basically understands everything + * as Length, and in addition to that provides a mapping for the border-width's + * thin, medium and think values. + */ +public class BorderWidth + extends Length +{ + + /** + * Creates a new BorderWidth instance. + * + * @param val the CSS value to be interpreted + */ + public BorderWidth(String val) + { + super(val); + if (val.equals("thin")) + floatValue = 1.F; + else if (val.equals("medium")) + floatValue = 2.F; + else if (val.equals("thick")) + floatValue = 3.F; + } + + /** + * Checks if the specified value makes up a valid border-width value. + * + * @param value the value to check + * + * @return true if the value is a valid border-width + */ + public static boolean isValid(String value) + { + return value.equals("thin") || value.equals("medium") + || value.equals("thick") || Length.isValid(value); + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/CSSColor.java b/libjava/classpath/gnu/javax/swing/text/html/css/CSSColor.java new file mode 100644 index 000000000..ea4b94ae0 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/CSSColor.java @@ -0,0 +1,170 @@ +/* CSSColor.java -- Converts CSS color values + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.css; + +import java.awt.Color; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Set; + +/** + * Converts CSS color values into AWT Color values. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class CSSColor +{ + + private static final HashMap COLOR_MAP; + static + { + COLOR_MAP = new HashMap(); + COLOR_MAP.put("maroon", "#800000"); + COLOR_MAP.put("red", "#ff0000"); + COLOR_MAP.put("orange", "#ffa500"); + COLOR_MAP.put("yellow", "#ffff00"); + COLOR_MAP.put("olive", "#808000"); + COLOR_MAP.put("purple", "#800080"); + COLOR_MAP.put("fuchsia", "#ff00ff"); + COLOR_MAP.put("white", "#ffffff"); + COLOR_MAP.put("lime", "#00ff00"); + COLOR_MAP.put("green", "#008000"); + COLOR_MAP.put("navy", "#000080"); + COLOR_MAP.put("blue", "#0000ff"); + COLOR_MAP.put("aqua", "#00ffff"); + COLOR_MAP.put("teal", "#008080"); + COLOR_MAP.put("black", "#000000"); + COLOR_MAP.put("silver", "#c0c0c0"); + COLOR_MAP.put("gray", "#808080"); + } + + /** + * The CSS value. + */ + private String value; + + /** + * The converted color. + */ + private Color color; + + /** + * Creates a new instance. + * + * @param val the CSS value + */ + public CSSColor(String val) + { + value = val; + color = convertValue(value); + } + + /** + * Converts a CSS color value to an AWT color. + * + * @param value the CSS color value + * + * @return the converted color value + */ + public static Color convertValue(String value) + { + Color color; + String val1 = value.toLowerCase(); + if (val1.charAt(0) != '#') + val1 = (String) COLOR_MAP.get(val1); + if (val1 != null) + { + String hexVal = val1.substring(1).trim(); + try + { + int rgb = Integer.parseInt(hexVal, 16); + color = new Color(rgb); + } + catch (NumberFormatException ex) + { + color = Color.BLACK; + } + } + else + color = null; + return color; + } + + /** + * Returns the converted color. + * + * @return the converted color + */ + public Color getValue() + { + return color; + } + + public String toString() + { + return value; + } + + /** + * Returns true if the specified value is a valid color value, + * false otherwise. + * + * @param val the value to check + * + * @return true if the specified value is a valid color value, + * false otherwise + */ + public static boolean isValidColor(String val) + { + boolean ret = false; + if (val.charAt(0) == '#') + ret = true; + else + { + Set colors = COLOR_MAP.keySet(); + for (Iterator i = colors.iterator(); i.hasNext() && ret == false;) + { + String color = (String) i.next(); + if (color.equalsIgnoreCase(val)) + ret = true; + } + } + return ret; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/CSSLexicalException.java b/libjava/classpath/gnu/javax/swing/text/html/css/CSSLexicalException.java new file mode 100644 index 000000000..13968e4d2 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/CSSLexicalException.java @@ -0,0 +1,60 @@ +/* CSSLexicalException.java -- Indicates a failure in the lexical analyser + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.css; + +import java.io.IOException; + +/** + * Indicates a failure in the lexical analyser of the CSS parser. + */ +public class CSSLexicalException + extends IOException +{ + + public CSSLexicalException() + { + super(); + } + + public CSSLexicalException(String message) + { + super(message); + } + +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/CSSParser.java b/libjava/classpath/gnu/javax/swing/text/html/css/CSSParser.java new file mode 100644 index 000000000..4be315e37 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/CSSParser.java @@ -0,0 +1,503 @@ +/* CSSParser.java -- A parser for CSS stylesheets + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.css; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.StringTokenizer; + +/** + * A parser for CSS stylesheets. + * + * This parser is based on the simple CSS grammar describe in + * + * http://www.w3.org/TR/CSS21/syndata.html . + * + * @author Roman Kennke (kennke@aicas.com) + */ +// TODO: Maybe use more restrictive grammar: +// http://www.w3.org/TR/CSS21/grammar.html#q1 +public class CSSParser +{ + + /** + * The scanner used to read the input streams into more usable tokens. + */ + private CSSScanner scanner; + + /** + * The parser callback. + */ + private CSSParserCallback callback; + + /** + * One lookahead token. + */ + private int lookahead; + + /** + * The parse error. + */ + private String error; + + /** + * Creates a new CSSParser that parses the specified input. + * + * @param in the source to parse + */ + public CSSParser(Reader in, CSSParserCallback cb) + { + scanner = new CSSScanner(in); + callback = cb; + lookahead = -1; + } + + /** + * Parses the input source specified in the constructor. + * + * @throws IOException if an IO or parse error occurs + */ + public void parse() + throws IOException + { + boolean success = parseStylesheet(); + if (! success) + { + throw new CSSParserException(error); + } + } + + /** + * Parses a stylesheet. + * + * @return true if the stylesheet could be parsed successfully, + * false otherwise + * + * @throws IOException if an IO or parse error occurs + */ + private boolean parseStylesheet() + throws IOException + { + int token = peekToken(); + while (token != CSSScanner.EOF && (token == CSSScanner.CDC + || token == CSSScanner.CDO || token == CSSScanner.S + || parseStatement())) + { + if (token == CSSScanner.CDC || token == CSSScanner.CDO + || token == CSSScanner.S) + readToken(); + token = peekToken(); + } + // Last token must be EOF for valid stylesheets, I'd think. + return token == CSSScanner.EOF; + } + + /** + * Parses a CSS statement. + * @return true if the stylesheet could be parsed successfully, + * false otherwise + * + * @throws IOException if an IO or parse error occurs + */ + private boolean parseStatement() + throws IOException + { + return parseRuleset() || parseAtRule(); + } + + /** + * Parses a CSS rule set. + * + * @return true if the ruleset could be parsed successfully, + * false otherwise + * + * @throws IOException if an IO or parse error occurs + */ + private boolean parseRuleset() + throws IOException + { + StringBuilder selector = new StringBuilder(); + parseSelector(selector); + StringTokenizer selSplitter = + new StringTokenizer(selector.toString(), ","); + Selector[] sels = new Selector[selSplitter.countTokens()]; + for (int i = 0; selSplitter.hasMoreTokens(); i++) + { + String sel = selSplitter.nextToken().trim(); + sels[i] = new Selector(sel); + } + callback.startStatement(sels); + // Read any number of whitespace. + int token; + do + { + token = readToken(); + } while (token == CSSScanner.S); + boolean ret = true; + + if (token == CSSScanner.CURLY_LEFT) + { + // Read any number of whitespace. + do + { + token = readToken(); + } while (token == CSSScanner.S); + lookahead = token; + + // Maybe read declaration. + boolean decl = parseDeclaration(); + token = peekToken(); + while (token == CSSScanner.SEMICOLON) + { + readToken(); // Read the semicolon. + // Read any number of whitespace. + do + { + token = readToken(); + } while (token == CSSScanner.S); + lookahead = token; + + // Maybe read declaration. + parseDeclaration(); + token = peekToken(); + } + if (token != CSSScanner.CURLY_RIGHT) + { + error = "Expected right curly brace"; + ret = false; + } + else + { + readToken(); + // Read any number of whitespace. + do + { + token = readToken(); + } while (token == CSSScanner.S); + lookahead = token; + callback.endStatement(); + } + } + else + { + ret = false; + error = "Expected left curly brace"; + } + return ret; + } + + /** + * Parses a CSS declaration. + * + * @return true if the ruleset could be parsed successfully, + * false otherwise + * + * @throws IOException if an IO or parse error occurs + */ + private boolean parseDeclaration() + throws IOException + { + // Maybe fetch one DELIM. + int token = readToken(); + if (token == CSSScanner.DELIM) + token = readToken(); + + boolean ret = true; + + // Parse property + String property = null; + if (token == CSSScanner.IDENT) + { + property = new String(scanner.parseBuffer, 0, scanner.tokenEnd); + // Read any number of whitespace. + do + { + token = readToken(); + } while (token == CSSScanner.S); + + // Read ':'. + if (token == CSSScanner.DELIM && scanner.parseBuffer[0] == ':') + { + // Read any number of whitespace. + do + { + token = readToken(); + } while (token == CSSScanner.S); + lookahead = token; + + StringBuilder value = new StringBuilder(); + if (parseValue(value)) + { + callback.declaration(property, value.toString().trim()); + } + else + { + ret = false; + error = "Error while reading the property value"; + } + } + else + { + ret = false; + error = "Expected colon to separate property and value"; + } + + } + else + { + lookahead = token; + ret = false; + error = "Expected IDENT token for property"; + } + return ret; + } + + /** + * Parses a property value. + * + * @param s the string builder to read the value into + * + * @return true if the ruleset could be parsed successfully, + * false otherwise + * + * @throws IOException if an IO or parse error occurs + */ + private boolean parseValue(StringBuilder s) + throws IOException + { + // FIXME: Handle block and ATKEYWORD. + boolean success = parseAny(s); + while (parseAny(s)) + ; + + return success; + } + + /** + * Parses a selector. + * + * @param sel the string buffer to put the selector into + * + * @return true if the ruleset could be parsed successfully, + * false otherwise + * + * @throws IOException if an IO or parse error occurs + */ + private boolean parseSelector(StringBuilder sel) + throws IOException + { + // At least one any needs to be parsed. + boolean ret = parseAny(sel); + if (ret) + { + while (parseAny(sel)) + ; + } + return ret; + } + + /** + * Parses the any rule. If s is not null, then the contents of the + * tokens is appended verbatim. + * + * @param s the string builder to append to + * + * @return true if the ruleset could be parsed successfully, + * false otherwise + * + * @throws IOException if an IO or parse error occurs + */ + private boolean parseAny(StringBuilder s) + throws IOException + { + int token = peekToken(); + boolean ret = false; + if (token == CSSScanner.IDENT || token == CSSScanner.NUMBER + || token == CSSScanner.PERCENTAGE || token == CSSScanner.DIMENSION + || token == CSSScanner.STRING || token == CSSScanner.DELIM + || token == CSSScanner.URI || token == CSSScanner.HASH + || token == CSSScanner.UNICODE_RANGE || token == CSSScanner.INCLUDES + || token == CSSScanner.DASHMATCH) + { + if (s != null) + s.append(scanner.parseBuffer, 0, scanner.tokenEnd); + readToken(); + ret = true; + } + else if (token == CSSScanner.FUNCTION) + System.err.println("Implement parseAny for FUNCTION"); + else if (token == CSSScanner.PAREN_LEFT) + System.err.println("Implement parseAny for ("); + else if (token == CSSScanner.BRACE_LEFT) + System.err.println("Implement parseAny for ["); + + // Parse any following whitespace too. + token = peekToken(); + while (token == CSSScanner.S) + { + if (s != null) + s.append(scanner.parseBuffer, 0, scanner.tokenEnd); + readToken(); + token = peekToken(); + } + return ret; + } + + /** + * Parses a CSS at-rule. + * + * @return true if the at-rule could be parsed successfully, + * false otherwise + * + * @throws IOException if an IO or parse error occurs + */ + private boolean parseAtRule() + throws IOException + { + // FIXME: Implement. + return false; + } + + /** + * Reads the next token, and skips the comments. + * + * @return the next non-comment token + */ + private int readToken() + throws IOException + { + int token; + if (lookahead == -1) + { + do + { + token = scanner.nextToken(); + } while (token == CSSScanner.COMMENT); + } + else + { + token = lookahead; + lookahead = -1; + } + return token; + } + + /** + * Returns the next token to be read, without really reading it. The next + * call to readToken() will return the same token again. + * + * @return the next token to be read, without really reading it + */ + private int peekToken() + throws IOException + { + int token; + if (lookahead == -1) + { + do + { + token = scanner.nextToken(); + } while (token == CSSScanner.COMMENT); + lookahead = token; + } + else + token = lookahead; + return token; + } + + /** + * For testing, we read in the default.css in javax/swing/text/html + * + * @param args + */ + public static void main(String[] args) + { + try + { + InputStream in; + if (args.length > 0) + { + File file = new File(args[0]); + in = new FileInputStream(file); + } + else + { + String name = "/javax/swing/text/html/default.css"; + in = CSSScanner.class.getResourceAsStream(name); + } + BufferedInputStream bin = new BufferedInputStream(in); + InputStreamReader r = new InputStreamReader(bin); + CSSParserCallback cb = new CSSParserCallback() + { + public void startStatement(Selector[] selector) + { + System.out.print("startStatement: "); + for (int i = 0; i < selector.length; i++) + { + System.out.print(selector[i]); + if (i < selector.length - 1) + System.out.print(','); + else + System.out.println(); + } + } + public void endStatement() + { + System.out.println("endStatement"); + } + public void declaration(String property, String value) + { + System.out.println("declaration: " + property + ", " + value); + } + }; + CSSParser p = new CSSParser(r, cb); + p.parse(); + } + catch (IOException ex) + { + ex.printStackTrace(); + } + } + +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/CSSParserCallback.java b/libjava/classpath/gnu/javax/swing/text/html/css/CSSParserCallback.java new file mode 100644 index 000000000..f49ffa232 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/CSSParserCallback.java @@ -0,0 +1,81 @@ +/* CSSParserCallback.java -- Callback for parsing CSS + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.css; + +/** + * Defines the callback that is used by the CSSParser to notify the + * backend of the parsing process. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public interface CSSParserCallback +{ + + /** + * Signals the beginning of a statement. + * + * A CSS statement is build up like follows: + *
    +   *  {
    +   *   ... declarations...
    +   * }
    +   * 
    + * + * After startStatement(), the callback will receive zero to n callbacks + * to declaration, followed by an endStatement() call. + * + * @param selector the selector of the statement. + */ + void startStatement(Selector[] selector); + + /** + * Signals the end of a statement. + */ + void endStatement(); + + /** + * Signals the parsing of one declaration, which defines a mapping + * from a property to a value. + * + * @param property the property + * @param value the value + */ + void declaration(String property, String value); + +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/CSSParserException.java b/libjava/classpath/gnu/javax/swing/text/html/css/CSSParserException.java new file mode 100644 index 000000000..2328d5398 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/CSSParserException.java @@ -0,0 +1,62 @@ +/* CSSParserException.java -- The CSS parser exception + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.css; + +import java.io.IOException; + +/** + * This exception is raised when the CSS parser hits a syntax error. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class CSSParserException + extends IOException +{ + + /** + * Creates a new CSSParserException. + * + * @param message the exception message + */ + public CSSParserException(String message) + { + super(message); + } + +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/CSSScanner.java b/libjava/classpath/gnu/javax/swing/text/html/css/CSSScanner.java new file mode 100644 index 000000000..37d544641 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/CSSScanner.java @@ -0,0 +1,718 @@ +/* CSSScanner.java -- A parser for CSS stylesheets + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.css; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; + +/** + * A tokenizer for CSS stylesheets. This is based on the scanner definition + * from: + * + * http://www.w3.org/TR/CSS21/syndata.html#tokenization + * + * @author Roman Kennke (kennke@aicas.com) + */ +// TODO: Maybe implement more restrictive scanner: +// http://www.w3.org/TR/CSS21/grammar.html#q2 +class CSSScanner +{ + + // The tokens. This list is taken from: + // http://www.w3.org/TR/CSS21/syndata.html#tokenization + static final int IDENT = 1; + static final int ATKEYWORD = 2; + static final int STRING = 3; + static final int INVALID = 4; + static final int HASH = 5; + static final int NUMBER = 6; + static final int PERCENTAGE = 7; + static final int DIMENSION = 8; + static final int URI = 9; + static final int UNICODE_RANGE = 10; + static final int CDO = 11; + static final int CDC = 12; + static final int SEMICOLON = 13; + static final int CURLY_LEFT = 14; + static final int CURLY_RIGHT = 15; + static final int PAREN_LEFT = 16; + static final int PAREN_RIGHT = 17; + static final int BRACE_LEFT = 16; + static final int BRACE_RIGHT = 17; + static final int S = 18; + static final int COMMENT = 19; + static final int FUNCTION = 20; + static final int INCLUDES = 21; + static final int DASHMATCH = 22; + static final int DELIM = 23; + + // Additional tokens defined for convenience. + static final int EOF = -1; + + /** + * The input source. + */ + private Reader in; + + /** + * The parse buffer. + */ + char[] parseBuffer; + + /** + * The end index in the parseBuffer of the current token. + */ + int tokenEnd; + + /** + * The lookahead 'buffer'. + */ + private int[] lookahead; + + CSSScanner(Reader r) + { + lookahead = new int[2]; + lookahead[0] = -1; + lookahead[1] = -1; + parseBuffer = new char[2048]; + in = r; + } + + /** + * Fetches the next token. The actual character data is in the parseBuffer + * afterwards with the tokenStart at index 0 and the tokenEnd field + * pointing to the end of the token. + * + * @return the next token + */ + int nextToken() + throws IOException + { + tokenEnd = 0; + int token = -1; + int next = read(); + if (next != -1) + { + switch (next) + { + case ';': + parseBuffer[0] = (char) next; + tokenEnd = 1; + token = SEMICOLON; + break; + case '{': + parseBuffer[0] = (char) next; + tokenEnd = 1; + token = CURLY_LEFT; + break; + case '}': + parseBuffer[0] = (char) next; + tokenEnd = 1; + token = CURLY_RIGHT; + break; + case '(': + parseBuffer[0] = (char) next; + tokenEnd = 1; + token = PAREN_LEFT; + break; + case ')': + parseBuffer[0] = (char) next; + tokenEnd = 1; + token = PAREN_RIGHT; + break; + case '[': + parseBuffer[0] = (char) next; + tokenEnd = 1; + token = BRACE_LEFT; + break; + case ']': + parseBuffer[0] = (char) next; + tokenEnd = 1; + token = BRACE_RIGHT; + break; + case '@': + parseBuffer[0] = (char) next; + tokenEnd = 1; + readIdent(); + token = ATKEYWORD; + break; + case '#': + parseBuffer[0] = (char) next; + tokenEnd = 1; + readName(); + token = HASH; + break; + case '\'': + case '"': + lookahead[0] = next; + readString(); + token = STRING; + break; + case ' ': + case '\t': + case '\r': + case '\n': + case '\f': + lookahead[0] = next; + readWhitespace(); + token = S; + break; + // FIXME: Detecting an URI involves several characters lookahead. +// case 'u': +// lookahead[0] = ch; +// readURI(); +// token = URI; +// break; + case '<': + parseBuffer[0] = (char) next; + parseBuffer[1] = (char) read(); + parseBuffer[2] = (char) read(); + parseBuffer[3] = (char) read(); + if (parseBuffer[1] == '!' && parseBuffer[2] == '-' + && parseBuffer[3] == '-') + { + token = CDO; + tokenEnd = 4; + } + else + throw new CSSLexicalException("expected CDO token"); + break; + case '/': + lookahead[0] = next; + readComment(); + token = COMMENT; + break; + case '~': + parseBuffer[0] = (char) next; + parseBuffer[1] = (char) read(); + if (parseBuffer[1] == '=') + token = INCLUDES; + else + throw new CSSLexicalException("expected INCLUDES token"); + break; + case '|': + parseBuffer[0] = (char) next; + parseBuffer[1] = (char) read(); + if (parseBuffer[1] == '=') + token = DASHMATCH; + else + throw new CSSLexicalException("expected DASHMATCH token"); + break; + case '-': + int ch2 = read(); + if (ch2 == '-') + { + int ch3 = read(); + if (ch3 == '>') + { + parseBuffer[0] = (char) next; + parseBuffer[1] = (char) ch2; + parseBuffer[2] = (char) ch3; + tokenEnd = 3; + token = CDC; + } + else + throw new CSSLexicalException("expected CDC token"); + } + else + { + lookahead[0] = next; + lookahead[1] = ch2; + readIdent(); + int ch3 = read(); + if (ch3 == -1 || ch3 != '(') + { + lookahead[0] = ch3; + token = IDENT; + } + else + { + parseBuffer[tokenEnd] = (char) ch3; + tokenEnd++; + token = FUNCTION; + } + } + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + lookahead[0] = next; + readNum(); + int ch3 = read(); + if (ch3 == '%') + { + parseBuffer[tokenEnd] = (char) ch3; + tokenEnd++; + token = PERCENTAGE; + } + else if (ch3 == -1 || (! (ch3 == '_' + || (ch3 >= 'a' && ch3 <= 'z') + || (ch3 >= 'A' && ch3 <= 'Z') + || ch3 == '\\' || ch3 > 177))) + { + lookahead[0] = ch3; + token = NUMBER; + } + else + { + lookahead[0] = ch3; + readIdent(); + token = DIMENSION; + } + break; + default: + // Handle IDENT that don't begin with '-'. + if (next == '_' || (next >= 'a' && next <= 'z') + || (next >= 'A' && next <= 'Z') || next == '\\' || next > 177) + { + lookahead[0] = next; + readIdent(); + int ch4 = read(); + if (ch4 == -1 || ch4 != '(') + { + lookahead[0] = ch4; + token = IDENT; + } + else + { + parseBuffer[tokenEnd] = (char) ch4; + tokenEnd++; + token = FUNCTION; + } + } + else + { + parseBuffer[0] = (char) next; + tokenEnd = 1; + token = DELIM; + } + break; + } + } + return token; + } + + String currentTokenString() + { + return new String(parseBuffer, 0, tokenEnd); + } + + /** + * Reads one character from the input stream or from the lookahead + * buffer, if it contains one character. + * + * @return the next character + * + * @throws IOException if problems occur on the input source + */ + private int read() + throws IOException + { + int ret; + if (lookahead[0] != -1) + { + ret = lookahead[0]; + lookahead[0] = -1; + } + else if (lookahead[1] != -1) + { + ret = lookahead[1]; + lookahead[1] = -1; + } + else + { + ret = in.read(); + } + return ret; + } + + /** + * Reads and identifier. + * + * @throws IOException if something goes wrong in the input source or if + * the lexical analyser fails to read an identifier + */ + private void readIdent() + throws IOException + { + int ch1 = read(); + // Read possibly leading '-'. + if (ch1 == '-') + { + parseBuffer[tokenEnd] = (char) ch1; + tokenEnd++; + ch1 = read(); + } + // What follows must be '_' or a-z or A-Z or nonascii (>177) or an + // escape. + if (ch1 == '_' || (ch1 >= 'a' && ch1 <= 'z') + || (ch1 >= 'A' && ch1 <= 'Z') || ch1 > 177) + { + parseBuffer[tokenEnd] = (char) ch1; + tokenEnd++; + } + else if (ch1 == '\\') + { + // Try to read an escape. + lookahead[0] = ch1; + readEscape(); + } + else + throw new CSSLexicalException("First character of identifier incorrect"); + + // Read any number of [_a-zA-Z0-9-] chars. + int ch = read(); + while (ch != -1 && (ch == '_' || ch == '-' || (ch >= 'a' && ch <= 'z') + || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9'))) + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + ch = read(); + } + + // Push back last read character since it doesn't belong to the IDENT. + lookahead[0] = ch; + } + + /** + * Reads an escape. + * + * @throws IOException if something goes wrong in the input source or if + * the lexical analyser fails to read an escape + */ + private void readEscape() + throws IOException + { + int ch = read(); + if (ch != -1 && ch == '\\') + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + ch = read(); + if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f')) + { + // Read unicode escape. + // Zero to five 0-9a-f chars can follow. + int hexcount = 0; + ch = read(); + while (((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f')) + && hexcount < 5) + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + hexcount++; + ch = read(); + } + // Now we can have a \r\n or any whitespace character following. + if (ch == '\r') + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + ch = read(); + if (ch == '\n') + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + } + else + { + lookahead[0] = ch; + } + } + else if (ch == ' ' || ch == '\n' || ch == '\f' || ch == '\t') + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + } + else + { + lookahead[0] = ch; + } + } + else if (ch != '\n' && ch != '\r' && ch != '\f') + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + } + else + throw new CSSLexicalException("Can't read escape"); + } + else + throw new CSSLexicalException("Escape must start with '\\'"); + + } + + private void readName() + throws IOException + { + // Read first name character. + int ch = read(); + if (ch != -1 && (ch == '_' || ch == '-' || (ch >= 'a' && ch <= 'z') + || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9'))) + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + } + else + throw new CSSLexicalException("Invalid name"); + + // Read any number (at least one) of [_a-zA-Z0-9-] chars. + ch = read(); + while (ch != -1 && (ch == '_' || ch == '-' || (ch >= 'a' && ch <= 'z') + || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9'))) + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + ch = read(); + } + + // Push back last read character since it doesn't belong to the IDENT. + lookahead[0] = ch; + } + + /** + * Reads in a string. + * + * @throws IOException + */ + private void readString() + throws IOException + { + int ch1 = read(); + if (ch1 != -1 && (ch1 == '\'' || ch1 == '\"')) + { + parseBuffer[tokenEnd] = (char) ch1; + tokenEnd++; + + // Read any number of chars until we hit another chc1 char. + // Reject newlines, except if prefixed with \. + int ch = read(); + while (ch != -1 && ch != ch1) + { + // Every non-newline and non-\ char should be ok. + if (ch != '\n' && ch != '\r' && ch != '\f' && ch != '\\') + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + } + // Ok when followed by newline or as part of escape. + else if (ch == '\\') + { + int ch2 = read(); + if (ch2 == '\n' || ch2 == '\r') + { + parseBuffer[tokenEnd] = (char) ch; + parseBuffer[tokenEnd + 1] = (char) ch2; + tokenEnd += 2; + } + else + { + // Try to parse an escape. + lookahead[0] = ch; + lookahead[1] = ch2; + readEscape(); + } + } + else + throw new CSSLexicalException("Invalid string"); + + ch = read(); + } + if (ch != -1) + { + // Push the final char on the buffer. + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + } + else + throw new CSSLexicalException("Unterminated string"); + } + else + throw new CSSLexicalException("Invalid string"); + } + + /** + * Reads a chunk of whitespace. + * + * @throws IOException + */ + private void readWhitespace() + throws IOException + { + int ch = read(); + while (ch != -1 && (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' + || ch == '\f')) + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + ch = read(); + } + // Push back last character read. + lookahead[0] = ch; + + } + + private void readURI() + throws IOException + { + // FIXME: Implement. + } + + /** + * Reads a comment block. + * + * @throws IOException + */ + private void readComment() + throws IOException + { + // First we need a / and a * + int ch = read(); + if (ch != -1 && ch == '/') + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + ch = read(); + if (ch != -1 && ch == '*') + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + ch = read(); + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + boolean finished = false; + int lastChar = ch; + ch = read(); + while (! finished && ch != -1) + { + if (lastChar == '*' && ch == '/') + finished = true; + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + lastChar = ch; + ch = read(); + } + } + } + if (ch == -1) + throw new CSSLexicalException("Unterminated comment"); + + // Push back last character read. + lookahead[0] = ch; + } + + /** + * Reads a number. + * + * @throws IOException + */ + private void readNum() + throws IOException + { + boolean hadDot = false; + // First char must be number or . + int ch = read(); + if (ch != -1 && ((ch >= '0' && ch <= '9') || ch == '.')) + { + if (ch == '.') + hadDot = true; + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + // Now read in any number of digits afterwards, and maybe one dot, + // if we hadn't one already. + ch = read(); + while (ch != -1 && ((ch >= '0' && ch <= '9') + || (ch == '.' && ! hadDot))) + { + if (ch == '.') + hadDot = true; + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + ch = read(); + } + } + else + throw new CSSLexicalException("Invalid number"); + + // Check if we haven't accidentally finished with a dot. + if (parseBuffer[tokenEnd - 1] == '.') + throw new CSSLexicalException("Invalid number"); + + // Push back last character read. + lookahead[0] = ch; + } + + /** + * For testing, we read in the default.css in javax/swing/text/html + * + * @param args + */ + public static void main(String[] args) + { + try + { + String name = "/javax/swing/text/html/default.css"; + InputStream in = CSSScanner.class.getResourceAsStream(name); + BufferedInputStream bin = new BufferedInputStream(in); + InputStreamReader r = new InputStreamReader(bin); + CSSScanner s = new CSSScanner(r); + int token; + do + { + token = s.nextToken(); + System.out.println("token: " + token + ": " + + s.currentTokenString()); + } while (token != -1); + } + catch (IOException ex) + { + ex.printStackTrace(); + } + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/FontSize.java b/libjava/classpath/gnu/javax/swing/text/html/css/FontSize.java new file mode 100644 index 000000000..203eadc40 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/FontSize.java @@ -0,0 +1,273 @@ +/* FontSize.java -- Converts CSS font size values into real values + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.css; + +/** + * Converts CSS font-size values into real (point) values. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class FontSize +{ + + /** + * The CSS value. + */ + private String value; + + /** + * The actual font size. + */ + private int size; + + /** + * The index of one of the standard sizes that this font size maps to. + * This is -1 if this fontsize doesn't map to one of the standard sizes. + * + * @see #SCALE + */ + private int sizeIndex; + + /** + * True when this font size is relative. + */ + private boolean isRelative; + + /** + * The default size for 'medium' absolute size. The other absolute sizes + * are calculated from this. + */ + public static final int DEFAULT_FONT_SIZE = 12; + + /** + * The scaling factors relative to the medium size. Medium is at index 2. + */ + private static final double[] SCALE = {0.8, 0.9, 1.0, 1.2, 1.4, 1.6, 1.8 }; + + /** + * Creates a new FontSize for the specified value. + * + * @param val the value to convert + */ + public FontSize(String val) + { + value = val; + sizeIndex = -1; + isRelative = false; + size = mapValue(); + } + + /** + * Returns the font size value. + * + * @return the font size value + */ + public int getValue(int p) + { + if (isRelative) + mapRelative(p); + return size; + } + + public int getValue() + { + assert ! isRelative; + return size; + } + + /** + * Returns the converted real value in point. + * + * @return the converted real value in point + */ + private int mapValue() + { + int intVal; + if (value.contains("pt")) + intVal = mapPoints(); + else if (value.contains("px")) + intVal = mapPixels(); + else if (value.contains("em") || value.contains("%") + || value.contains("larger") || value.contains("smaller")) + { + intVal = -1; + isRelative = true; + } + else + intVal = mapAbsolute(); + return intVal; + } + + /** + * Maps point values ('XXXpt'). + * + * @return the real font size + */ + private int mapPoints() + { + int end = value.indexOf("pt"); + String number = value.substring(0, end); + int intVal = (int) Double.parseDouble(number); + return intVal; + } + + /** + * Maps pixel values ('XXXpx'). + * + * @return the real font size + */ + private int mapPixels() + { + int end = value.indexOf("px"); + if (end == -1) + end = value.length(); + String number = value.substring(0, end); + try + { + int intVal = (int) Double.parseDouble(number); + return intVal; + } + catch (NumberFormatException ex) + { + return DEFAULT_FONT_SIZE; + } + } + + private int mapPercent(int par) + { + int end = value.indexOf("%"); + if (end == -1) + end = value.length(); + String number = value.substring(0, end); + try + { + int intVal = (int) Double.parseDouble(number); + return intVal * par / 100; + } + catch (NumberFormatException ex) + { + System.err.println("couldn't map value: '" + value + "'"); + return DEFAULT_FONT_SIZE; + } + } + + private int mapEM(int par) + { + int end = value.indexOf("em"); + if (end == -1) + end = value.length(); + String number = value.substring(0, end); + try + { + float factor = Float.parseFloat(number); + // FIXME: Should be relative to the parent element's size. + return (int) (factor * par); + } + catch (NumberFormatException ex) + { + return DEFAULT_FONT_SIZE; + } + } + + private int mapSmaller(int par) + { + return (int) (par * 0.9); + } + + private int mapLarger(int par) + { + return (int) (par * 0.9); + } + + /** + * Maps absolute font-size values. + * + * @return the real value + */ + private int mapAbsolute() + { + int index; + if (value.equals("xx-small") || value.equals("x-small")) + index = 0; + else if (value.equals("small")) + index = 1; + else if (value.equals("medium")) + index = 2; + else if (value.equals("large")) + index = 3; + else if (value.equals("x-large")) + index = 4; + else if (value.equals("xx-large")) + index = 5; + else + index = 2; + double scale = SCALE[index]; + // FIXME: Scale the real medium size of the document, rather than the + // constant here. + int intVal = (int) (scale * DEFAULT_FONT_SIZE); + sizeIndex = index; + return intVal; + } + + /** + * Returns the string representation. + */ + public String toString() + { + return value; + } + + private int mapRelative(int par) + { + if (value.indexOf('%') != -1) + size = mapPercent(par); + else if (value.indexOf("em") != -1) + size = mapEM(par); + else if (value.indexOf("larger") != -1) + size = mapLarger(par); + else if (value.indexOf("smaller") != -1) + size = mapSmaller(par); + return size; + } + + public boolean isRelative() + { + return isRelative; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/FontStyle.java b/libjava/classpath/gnu/javax/swing/text/html/css/FontStyle.java new file mode 100644 index 000000000..e52893193 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/FontStyle.java @@ -0,0 +1,80 @@ +/* FontStyle.java -- Converts font-size CSS values + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.css; + +import java.awt.Font; + +/** + * Converts font-size CSS values to a form to be used by {@link java.awt.Font}. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class FontStyle +{ + + /** + * The real value. + */ + private String value; + + /** + * Creates a new instance. + * + * @param val the CSS value + */ + public FontStyle(String val) + { + value = val; + } + + /** + * Returns the converted value. + * + * @return the converted value + */ + public int getValue() + { + int intVal; + if (value.equals("italic") || value.equals("oblique")) + intVal = Font.ITALIC; + else + intVal = Font.PLAIN; + return intVal; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/FontWeight.java b/libjava/classpath/gnu/javax/swing/text/html/css/FontWeight.java new file mode 100644 index 000000000..d338c6f55 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/FontWeight.java @@ -0,0 +1,84 @@ +/* FontWeight.java -- Converts font-weight values + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.css; + +import java.awt.Font; + +/** + * Converts font-weight CSS values to the constants defined for + * {@link java.awt.Font} + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class FontWeight +{ + + /** + * The value to convert. + */ + private String value; + + /** + * Creates a new instance. + * + * @param val the value to convert + */ + public FontWeight(String val) + { + value = val; + } + + /** + * Returns the converted value. + * + * @return the converted value + */ + public int getValue() + { + int intVal; + if (value.equals("normal")) + intVal = Font.PLAIN; + else if (value.equals("bold")) + intVal = Font.BOLD; + else + // FIXME: Implement finer-grained weights. + intVal = Font.PLAIN; + return intVal; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/Length.java b/libjava/classpath/gnu/javax/swing/text/html/css/Length.java new file mode 100644 index 000000000..06fa36e3d --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/Length.java @@ -0,0 +1,283 @@ +/* Length.java -- Converts CSS length values + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.css; + +/** + * Converts CSS length values to usable length values. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class Length +{ + + /** + * The original value. + */ + private String value; + + /** + * The converted value. + */ + protected float floatValue; + + /** + * Indicates when the value is a percentage value. + */ + private boolean isPercentage; + + /** + * Indicates a length value that is relative to the font size (em). + */ + private boolean isFontEMRelative; + + /** + * Indicates a length value that is relative to the font size (ex). + */ + private boolean isFontEXRelative; + + /** + * The EM base size. + */ + private float emBase; + + /** + * The EX base size. + */ + private float exBase; + + /** + * Creates a new length converter instance. + * + * @param val the CSS value + */ + public Length(String val) + { + isFontEMRelative = false; + isFontEXRelative = false; + isPercentage = false; + value = val; + int i = value.indexOf("px"); + int percent = value.indexOf("%"); + int em = value.indexOf("em"); + int ex = value.indexOf("ex"); + try + { + floatValue = 0.0F; + if (i != -1) + { + String sub = value.substring(0, i); + floatValue = Float.parseFloat(sub); + } + else if (percent != -1) + { + isPercentage = true; + String sub = value.substring(0, percent); + floatValue = Float.parseFloat(sub) / 100; + } + else if (em != -1) + { + isFontEMRelative = true; + String sub = value.substring(0, em); + floatValue = Float.parseFloat(sub); + } + else if (ex != -1) + { + isFontEXRelative = true; + String sub = value.substring(0, ex); + floatValue = Float.parseFloat(sub); + } + else + { + floatValue = Float.parseFloat(value); + } + } + catch (NumberFormatException exc) + { + // Don't let such small problems interrupt CSS parsing. + System.err.println("couldn't parse: " + val); + } + } + + /** + * Returns the value converted to pixels. + * + * @return the value converted to pixels + */ + public float getValue() + { + return floatValue; + } + + /** + * Returns the absolute span for the case when this length value is + * a relative value. + * + * @param base the base span + * + * @return the absolute span + */ + public float getValue(float base) + { + float span = floatValue; + if (isPercentage) + span *= base; + else if (isFontEMRelative) + span *= emBase; + else if (isFontEXRelative) + span *= exBase; + return span; + } + + /** + * Sets the font relative EM base. + * + * @param base the font relative EM base + */ + public void setEMBase(float base) + { + emBase = base; + } + + /** + * Sets the font relative EX base. + * + * @param base the font relative EX base + */ + public void setEXBase(float base) + { + exBase = base; + } + + /** + * Sets the font relative base values. + * + * @param emBase the EM base + * @param exBase the EX base + */ + public void setFontBases(float emBase, float exBase) + { + setEMBase(emBase); + setEXBase(exBase); + } + + /** + * Returns true when this length value is an em font relative value. In + * order to get correct results, you need the exBase property set up + * correctly. + * + * @return true when this length value is an ex font relative value + */ + public boolean isFontEMRelative() + { + return isFontEMRelative; + } + + /** + * Returns true when this length value is an ex font relative value. In + * order to get correct results, you need the emBase property set up + * correctly. + * + * @return true when this length value is an ex font relative value + */ + public boolean isFontEXRelative() + { + return isFontEXRelative; + } + + /** + * Returns true when the length value is a percentage + * value, false otherwise. + * + * @return true when the length value is a percentage + * value, false otherwise + */ + public boolean isPercentage() + { + return isPercentage; + } + + /** + * Checks if the specified value makes up a valid length value. + * + * @param value the value to check + * + * @return true if the value is a valid length + */ + public static boolean isValid(String value) + { + boolean isValid = true; + int px = value.indexOf("px"); + int em = value.indexOf("em"); + int ex = value.indexOf("ex"); + int pc = value.indexOf('%'); + try + { + if (px != -1) + { + Integer.parseInt(value.substring(0, px)); + } + else if (em != -1) + { + Integer.parseInt(value.substring(0, em)); + } + else if (ex != -1) + { + Integer.parseInt(value.substring(0, ex)); + } + else if (pc != -1) + { + Integer.parseInt(value.substring(0, ex)); + } + else + { + Integer.parseInt(value); + } + } + catch (NumberFormatException nfe) + { + isValid = false; + } + return isValid; + } + + public String toString() + { + return value; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/Selector.java b/libjava/classpath/gnu/javax/swing/text/html/css/Selector.java new file mode 100644 index 000000000..97e582194 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/Selector.java @@ -0,0 +1,245 @@ +/* Selector.java -- A CSS selector + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.css; + +import gnu.java.lang.CPStringBuilder; + +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +/** + * A CSS selector. This provides methods to interpret a selector and + * query matches with an actual HTML element tree. + */ +public class Selector +{ + + /** + * The actual selector. The selector tokens are stored backwards, that + * is the last token first. This makes matching easier. + */ + private String[] selector; + + private String[] elements; + private String[] ids; + private String[] classes; + + /** + * The specificity of the selector. + */ + private int specificity; + + /** + * An implicit selector has true here. This is the case for CSS rules that + * are attached to HTML elements directly via style="". + */ + private boolean implicit; + + /** + * Creates a new Selector instance for the specified selector string. + * + * @param sel the selector + */ + public Selector(String sel) + { + StringTokenizer selectorTokens = new StringTokenizer(sel, " "); + selector = new String[selectorTokens.countTokens()]; + for (int i = selector.length - 1; selectorTokens.hasMoreTokens(); i--) + { + selector[i] = selectorTokens.nextToken(); + } + calculateSpecificity(); + } + + /** + * Determines if this selector matches the element path specified in the + * arguments. The arguments hold the element names as well as class + * and id attibutes of the HTML element to be queried. The first item + * in the array is the deepest element and the last on the highest up (for + * instance, the html tag). + * + * @param tags + * + * @return true when this selector matches the element path, + * false otherwise + */ + public boolean matches(String[] tags, List> attributes) + { + // TODO: This implements class, id and descendent matching. These are + // the most commonly used selector matchers in CSS together with HTML. + // However, the CSS spec defines a couple of more sophisticated matches + // which should be implemented. + // http://www.w3.org/TR/CSS21/selector.html + + // All parts of the selector must match at some point. + boolean match = false; + int numTags = tags.length; + int numSel = selector.length; + if (numSel <= numTags) + { + match = true; + int tagIndex = 0; + for (int j = 0; j < numSel && match; j++) + { + boolean tagMatch = false; + for (; tagIndex < numTags && tagMatch == false; tagIndex++) + { + Object pathClass = attributes.get(tagIndex).get("class"); + // Try pseudo class too. + Object pseudoClass = attributes.get(tagIndex).get("_pseudo"); + Object dynClass = attributes.get(tagIndex).get("_dynamic"); + Object pathId = attributes.get(tagIndex).get("id"); + String tag = elements[j]; + String clazz = classes[j]; + String id = ids[j]; + tagMatch = tag.equals("") || tag.equals("*") + || tag.equals(tags[tagIndex]); + tagMatch = tagMatch && (clazz.equals("*") + || clazz.equals(dynClass) + || clazz.equals(pseudoClass) + || clazz.equals(pathClass)); + tagMatch = tagMatch && (id.equals("*") + || id.equals(pathId)); + // For the last element in the selector we must not look + // further. + if (j == 0) + break; + } + // If we don't come out here with a matching tag, then we're + // not matching at all. + match = tagMatch; + } + } + return match; + } + + /** + * Returns the specificity of the selector. This is calculated according + * to: + * http://www.w3.org/TR/CSS21/cascade.html#specificity + * + * @return the specificity of the selector + */ + public int getSpecificity() + { + return specificity; + } + + /** + * Returns a string representation of the selector. This tries to reconstruct + * the original selector as closely as possible. + * + * @return a string representation of the selector + */ + public String toString() + { + CPStringBuilder b = new CPStringBuilder(); + for (int i = selector.length - 1; i >= 0; i--) + { + b.append(selector[i]); + if (i > 0) + b.append(' '); + } + return b.toString(); + } + + /** + * Calculates the specificity of the selector. This is calculated according + * to: + * http://www.w3.org/TR/CSS21/cascade.html#specificity + */ + private void calculateSpecificity() + { + int a = implicit ? 1 : 0; + int b = 0; + int c = 0; + int d = 0; + int numSel = selector.length; + elements = new String[numSel]; + ids = new String[numSel]; + classes = new String[numSel]; + for (int i = 0; i < numSel; i++) + { + String sel = selector[i]; + int clazzIndex = sel.indexOf('.'); + // Try pseudo class too. + if (clazzIndex == -1) + clazzIndex = sel.indexOf(':'); + int idIndex = sel.indexOf('#'); + String clazz; + if (clazzIndex == -1) + { + clazz = "*"; + clazzIndex = sel.length(); + } + else + { + c++; + clazz = sel.substring(clazzIndex + 1, + idIndex > 0 ? Math.min(idIndex, sel.length()) + : sel.length()); + } + String id; + if (idIndex == -1) + { + id = "*"; + idIndex = sel.length(); + } + else + { + b++; + id = sel.substring(idIndex + 1, + clazzIndex > 0 ? Math.min(clazzIndex, sel.length()) + : sel.length()); + } + String tag = sel.substring(0, + Math.min(Math.min(clazzIndex, idIndex), + sel.length())); + if (! tag.equals("") && ! tag.equals("*")) + d++; + + elements[i] = tag; + ids[i] = id; + classes[i] = clazz; + } + // An order of 20 should be enough for everybody. + specificity = a * 20 ^ 3 + b * 20 ^ 2 + c * 20 + d; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/package.html b/libjava/classpath/gnu/javax/swing/text/html/package.html new file mode 100644 index 000000000..c7e774428 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/package.html @@ -0,0 +1,50 @@ + + + + +GNU Classpath - javax.swing.text.html + + +

    Provides supporting classes for web browsers, + web robots, web page content analysers, web editors and + other applications applications working with Hypertext + Markup Language (HTML). +

    + + + diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/GnuParserDelegator.java b/libjava/classpath/gnu/javax/swing/text/html/parser/GnuParserDelegator.java new file mode 100644 index 000000000..9f3666d3a --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/GnuParserDelegator.java @@ -0,0 +1,179 @@ +/* GnuParserDelegator.java -- The parser delegator which uses Swing DTD + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.parser; + +import java.io.IOException; +import java.io.Reader; +import java.io.Serializable; + +import javax.swing.text.BadLocationException; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.html.HTMLEditorKit; +import javax.swing.text.html.HTMLEditorKit.ParserCallback; +import javax.swing.text.html.parser.DTD; +import javax.swing.text.html.parser.ParserDelegator; +import javax.swing.text.html.parser.TagElement; + +/** + * This parser delegator uses the different DTD ({@link HTML_401Swing}). + * It is derived from the ParserDelegator for the compatibility reasons. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class GnuParserDelegator extends ParserDelegator implements Serializable +{ + class gnuParser + extends gnu.javax.swing.text.html.parser.support.Parser + { + private static final long serialVersionUID = 1; + + gnuParser(DTD d) + { + super(d); + } + + protected final void handleComment(char[] comment) + { + callBack.handleComment(comment, hTag.where.startPosition); + } + + protected final void handleEmptyTag(TagElement tag) + throws javax.swing.text.ChangedCharSetException + { + callBack.handleSimpleTag(tag.getHTMLTag(), getAttributes(), + hTag.where.startPosition + ); + } + + protected final void handleEndTag(TagElement tag) + { + callBack.handleEndTag(tag.getHTMLTag(), hTag.where.startPosition); + } + + protected final void handleError(int line, String message) + { + callBack.handleError(message, hTag.where.startPosition); + } + + protected final void handleStartTag(TagElement tag) + { + SimpleAttributeSet attributes = gnu.getAttributes(); + + if (tag.fictional()) + attributes.addAttribute(ParserCallback.IMPLIED, Boolean.TRUE); + + callBack.handleStartTag(tag.getHTMLTag(), attributes, + hTag.where.startPosition + ); + } + + protected final void handleText(char[] text) + { + callBack.handleText(text, hTag.where.startPosition); + } + + DTD getDTD() + { + // Accessing the inherited gnu.javax.swing.text.html.parser.support.Parser + // field. super. is a workaround, required to support JDK1.3's javac. + return super.dtd; + } + } + + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = -1276686502624777206L; + + private DTD theDtd; + + /** + * The callback. + * This is package-private to avoid an accessor method. + */ + HTMLEditorKit.ParserCallback callBack; + + /** + * The reference to the working class of HTML parser that is + * actually used to parse the document. + * This is package-private to avoid an accessor method. + */ + gnuParser gnu; + + /** + * Create the parser that uses the given DTD to parse the document. + * + * @param theDtd the DTD + */ + public GnuParserDelegator(DTD theDtd) + { + this.theDtd = theDtd; + gnu = new gnuParser(theDtd); + } + + /** + * Parses the HTML document, calling methods of the provided callback. This + * method must be multithread - safe. + * + * @param reader The reader to read the HTML document from + * @param a_callback The callback that is notifyed about the presence of HTML + * elements in the document. + * @param ignoreCharSet If thrue, any charset changes during parsing are + * ignored. + * @throws java.io.IOException + */ + public void parse(Reader reader, + HTMLEditorKit.ParserCallback a_callback, + boolean ignoreCharSet) throws IOException + { + callBack = a_callback; + gnu.parse(reader); + + callBack.handleEndOfLineString(gnu.getEndOfLineSequence()); + try + { + callBack.flush(); + } + catch (BadLocationException ex) + { + // Convert this into the supported type of exception. + throw new IOException(ex.getMessage()); + } + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/HTML_401F.java b/libjava/classpath/gnu/javax/swing/text/html/parser/HTML_401F.java new file mode 100644 index 000000000..d4b061465 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/HTML_401F.java @@ -0,0 +1,3801 @@ +/* HTML_401F.java -- HTML 4.01 FRAMESET DTD java conception. + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.parser; + +import gnu.javax.swing.text.html.parser.models.PCDATAonly_model; +import gnu.javax.swing.text.html.parser.models.TableRowContentModel; +import gnu.javax.swing.text.html.parser.models.noTagModel; + +import java.io.IOException; +import java.io.Serializable; + +import javax.swing.text.html.parser.*; +import javax.swing.text.html.parser.ContentModel; +import javax.swing.text.html.parser.DTDConstants; + +/** + * This class represents the java implementation of the HTML 4.01 + * ( -//W3C//DTD HTML 4.01 Frameset//EN ) Frameset version. The + * Frameset version includes as recommended, as obsoleted features and + * also the frameset support. This the default DTD to parse HTML + * documents in this implementation, containing 315 pre-defined general + * entities and 92 elements. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class HTML_401F + extends gnuDTD + implements DTDConstants, Serializable +{ + private static final long serialVersionUID = 1; + + /** + * The standard name of this DTD, + * '-//W3C//DTD HTML 4.01 Frameset//EN' + */ + public static final String DTD_NAME = "-//W3C//DTD HTML 4.01 Frameset//EN"; + + /** + * The integer representing length in pixels. + */ + static final int PIXELS = NUMBER; + + static final String[] NONE = new String[0]; + + /* Define the HTML tags. */ + static final String PCDATA = "#pcdata"; + static final String A = "a"; + static final String ABBR = "abbr"; + static final String ACRONYM = "acronym"; + static final String ADDRESS = "address"; + static final String APPLET = "applet"; + static final String AREA = "area"; + static final String B = "b"; + static final String BASE = "base"; + static final String BASEFONT = "basefont"; + static final String BDO = "bdo"; + static final String BIG = "big"; + static final String BLOCKQUOTE = "blockquote"; + static final String BODY = "body"; + static final String BR = "br"; + static final String BUTTON = "button"; + static final String CAPTION = "caption"; + static final String CENTER = "center"; + static final String CITE = "cite"; + static final String CODE = "code"; + static final String COL = "col"; + static final String COLGROUP = "colgroup"; + static final String DEFAULTS = "default"; + static final String DD = "dd"; + static final String DEL = "del"; + static final String DFN = "dfn"; + static final String DIR = "dir"; + static final String DIV = "div"; + static final String DL = "dl"; + static final String DT = "dt"; + static final String EM = "em"; + static final String FIELDSET = "fieldset"; + static final String FONT = "font"; + static final String FORM = "form"; + static final String FRAME = "frame"; + static final String FRAMESET = "frameset"; + static final String H1 = "h1"; + static final String H2 = "h2"; + static final String H3 = "h3"; + static final String H4 = "h4"; + static final String H5 = "h5"; + static final String H6 = "h6"; + static final String HEAD = "head"; + static final String HR = "hr"; + static final String HTML = "html"; + static final String I = "i"; + static final String IFRAME = "iframe"; + static final String IMG = "img"; + static final String INPUT = "input"; + static final String INS = "ins"; + static final String ISINDEX = "isindex"; + static final String KBD = "kbd"; + static final String LABEL = "label"; + static final String LEGEND = "legend"; + static final String LI = "li"; + static final String LINK = "link"; + static final String MAP = "map"; + static final String MENU = "menu"; + static final String META = "meta"; + static final String NOFRAMES = "noframes"; + static final String NOSCRIPT = "noscript"; + static final String NONES = "none"; + static final String sNAME = "name"; + static final String OBJECT = "object"; + static final String OL = "ol"; + static final String OPTGROUP = "optgroup"; + static final String OPTION = "option"; + static final String P = "p"; + static final String PARAM = "param"; + static final String PRE = "pre"; + static final String Q = "q"; + static final String S = "s"; + static final String SAMP = "samp"; + static final String SCRIPT = "script"; + static final String SELECT = "select"; + static final String SMALL = "small"; + static final String SPAN = "span"; + static final String STRIKE = "strike"; + static final String STRONG = "strong"; + static final String STYLE = "style"; + static final String SUB = "sub"; + static final String SUP = "sup"; + static final String TABLE = "table"; + static final String TBODY = "tbody"; + static final String TD = "td"; + static final String TEXTAREA = "textarea"; + static final String TFOOT = "tfoot"; + static final String TH = "th"; + static final String THEAD = "thead"; + static final String TITLE = "title"; + static final String TR = "tr"; + static final String TT = "tt"; + static final String U = "u"; + static final String UL = "ul"; + static final String VAR = "var"; + + /* Define the attribute constants. */ + static final String C_0 = "0"; + static final String C_1 = "1"; + static final String CHECKBOX = "checkbox"; + static final String DATA = "data"; + static final String FILE = "file"; + static final String GET = "get"; + static final String HIDDEN = "hidden"; + static final String IMAGE = "image"; + static final String PASSWORD = "password"; + static final String POST = "post"; + static final String RADIO = "radio"; + static final String REF = "ref"; + static final String RESET = "reset"; + static final String SUBMIT = "submit"; + static final String TEXT = "text"; + static final String ABOVE = "above"; + static final String ACCEPT = "accept"; + static final String ACCEPTCHARSET = "accept-charset"; + static final String ACCESSKEY = "accesskey"; + static final String ACTION = "action"; + static final String ALIGN = "align"; + static final String ALINK = "alink"; + static final String ALL = "all"; + static final String ALT = "alt"; + static final String APPLICATION_X_WWW_FORM_URLENCODED + = "application/x-www-form-urlencoded"; + static final String ARCHIVE = "archive"; + static final String AUTO = "auto"; + static final String AXIS = "axis"; + static final String BACKGROUND = "background"; + static final String BASELINE = "baseline"; + static final String BELOW = "below"; + static final String BGCOLOR = "bgcolor"; + static final String BORDER = "border"; + static final String BOTTOM = "bottom"; + static final String BOX = "box"; + static final String CELLPADDING = "cellpadding"; + static final String CELLSPACING = "cellspacing"; + static final String CHAR = "char"; + static final String CHAROFF = "charoff"; + static final String CHARSET = "charset"; + static final String CHECKED = "checked"; + static final String CIRCLE = "circle"; + static final String CLASS = "class"; + static final String CLASSID = "classid"; + static final String CLEAR = "clear"; + static final String CODEBASE = "codebase"; + static final String CODETYPE = "codetype"; + static final String COLOR = "color"; + static final String COLS = "cols"; + static final String COLSPAN = "colspan"; + static final String COMPACT = "compact"; + static final String CONTENT = "content"; + static final String COORDS = "coords"; + static final String DATAPAGESIZE = "datapagesize"; + static final String DATETIME = "datetime"; + static final String DECLARE = "declare"; + static final String DEFER = "defer"; + static final String DISABLED = "disabled"; + static final String DISC = "disc"; + static final String ENCTYPE = "enctype"; + static final String EVENT = "event"; + static final String FACE = "face"; + static final String FOR = "for"; + static final String FRAMEBORDER = "frameborder"; + static final String GROUPS = "groups"; + static final String HEADERS = "headers"; + static final String HEIGHT = "height"; + static final String HREF = "href"; + static final String HREFLANG = "hreflang"; + static final String HSIDES = "hsides"; + static final String HSPACE = "hspace"; + static final String HTTPEQUIV = "http-equiv"; + static final String sID = "id"; + static final String ISMAP = "ismap"; + static final String JUSTIFY = "justify"; + static final String LANG = "lang"; + static final String LANGUAGE = "language"; + static final String LEFT = "left"; + static final String LHS = "lhs"; + static final String LONGDESC = "longdesc"; + static final String LTR = "ltr"; + static final String MARGINHEIGHT = "marginheight"; + static final String MARGINWIDTH = "marginwidth"; + static final String MAXLENGTH = "maxlength"; + static final String MEDIA = "media"; + static final String METHOD = "method"; + static final String MIDDLE = "middle"; + static final String MULTIPLE = "multiple"; + static final String NO = "no"; + static final String NOHREF = "nohref"; + static final String NORESIZE = "noresize"; + static final String NOSHADE = "noshade"; + static final String NOWRAP = "nowrap"; + static final String ONBLUR = "onblur"; + static final String ONCHANGE = "onchange"; + static final String ONCLICK = "onclick"; + static final String ONDBLCLICK = "ondblclick"; + static final String ONFOCUS = "onfocus"; + static final String ONKEYDOWN = "onkeydown"; + static final String ONKEYPRESS = "onkeypress"; + static final String ONKEYUP = "onkeyup"; + static final String ONLOAD = "onload"; + static final String ONMOUSEDOWN = "onmousedown"; + static final String ONMOUSEMOVE = "onmousemove"; + static final String ONMOUSEOUT = "onmouseout"; + static final String ONMOUSEOVER = "onmouseover"; + static final String ONMOUSEUP = "onmouseup"; + static final String ONRESET = "onreset"; + static final String ONSELECT = "onselect"; + static final String ONSUBMIT = "onsubmit"; + static final String ONUNLOAD = "onunload"; + static final String POLY = "poly"; + static final String PROFILE = "profile"; + static final String PROMPT = "prompt"; + static final String READONLY = "readonly"; + static final String RECT = "rect"; + static final String REL = "rel"; + static final String REV = "rev"; + static final String RHS = "rhs"; + static final String RIGHT = "right"; + static final String ROW = "row"; + static final String ROWGROUP = "rowgroup"; + static final String ROWS = "rows"; + static final String ROWSPAN = "rowspan"; + static final String RTL = "rtl"; + static final String RULES = "rules"; + static final String SCHEME = "scheme"; + static final String SCOPE = "scope"; + static final String SCROLLING = "scrolling"; + static final String SELECTED = "selected"; + static final String SHAPE = "shape"; + static final String SIZE = "size"; + static final String SQUARE = "square"; + static final String SRC = "src"; + static final String STANDBY = "standby"; + static final String START = "start"; + static final String SUMMARY = "summary"; + static final String TABINDEX = "tabindex"; + static final String TARGET = "target"; + static final String TOP = "top"; + static final String TYPE = "type"; + static final String USEMAP = "usemap"; + static final String VALIGN = "valign"; + static final String VALUE = "value"; + static final String VALUETYPE = "valuetype"; + static final String VERSION = "version"; + static final String VLINK = "vlink"; + static final String VOID = "void"; + static final String VSIDES = "vsides"; + static final String VSPACE = "vspace"; + static final String WIDTH = "width"; + static final String YES = "yes"; + + static final String[] BLOCK = + new String[] { + ADDRESS, BLOCKQUOTE, CENTER, DIR, + DIV, DL, FIELDSET, FORM, + H1, H2, H3, H4, H5, H6, + HR, ISINDEX, MENU, NOFRAMES, NOSCRIPT, + OL, P, PRE, TABLE, UL + }; + + /** + * Creates this DTD, filling in the entities and attributes data + * as defined in -//W3C//DTD HTML 4.01 Frameset//EN. + */ + protected HTML_401F() + { + super(DTD_NAME); + defineEntities(); + defineElements(); + } + + /** + * Either takes the document (by name) from DTD table, or + * creates a new instance and registers it in the tabe. + * The document is registerd under name "-//W3C//DTD HTML 4.01 Frameset//EN". + * @return The new or existing DTD for parsing HTML 4.01 Frameset. + */ + public static DTD getInstance() + { + try + { + DTD dtd = getDTD(DTD_NAME); + if (dtd == null || dtd.getClass().equals(DTD.class)) + { + dtd = new HTML_401F(); + putDTDHash(DTD_NAME, dtd); + } + return dtd; + } + catch (IOException ex) + { + throw new Error("This should never happen. Report the bug.", ex); + } + } + + /** + * Define all elements of this DTD. + */ + protected void defineElements() + { + /* Define the elements. This used to be one huge method, which + unfortunately took too long to compile and consumed + too much memory while compiling it. While it can serve as + a good stress test for gcj, it is better to split it up + to save time and memory used during GCC bootstrap. */ + defineElements1(); + defineElements2(); + defineElements3(); + defineElements4(); + defineElements5(); + defineElements6(); + } + + /** + * Define first sixth of elements of this DTD. + */ + private void defineElements1() + { + /* Define the elements. */ + defElement(PCDATA, 0, false, false, null, NONE, NONE, + new AttributeList[ 0 ]); + + defElement(A, 0, false, false, null, + new String[] { + A + } + , + new String[] { + PCDATA, ABBR, ACRONYM, APPLET, + B, BASEFONT, BDO, BIG, BR, + BUTTON, CITE, CODE, DFN, EM, + FONT, I, IFRAME, IMG, INPUT, + KBD, LABEL, MAP, OBJECT, Q, + S, SAMP, SCRIPT, SELECT, SMALL, + SPAN, STRIKE, STRONG, SUB, SUP, + TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(CHARSET, null, null, 0, IMPLIED), + attr(TYPE, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, IMPLIED), + attr(HREF, null, null, 0, IMPLIED), + attr(HREFLANG, null, null, 0, IMPLIED), + attr(TARGET, null, null, 0, IMPLIED), + attr(REL, null, null, 0, IMPLIED), + attr(REV, null, null, 0, IMPLIED), + attr(ACCESSKEY, null, null, 0, IMPLIED), + attr(SHAPE, RECT, new String[] { RECT, CIRCLE, POLY, DEFAULTS }, + 0, DEFAULT), + attr(COORDS, null, null, 0, IMPLIED), + attr(TABINDEX, null, null, NUMBER, IMPLIED), + attr(ONFOCUS, null, null, 0, IMPLIED), + attr(ONBLUR, null, null, 0, IMPLIED) + } + ); + defElement(ABBR, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(ACRONYM, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(ADDRESS, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + P + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(APPLET, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL, PARAM + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(CODEBASE, null, null, 0, IMPLIED), + attr(ARCHIVE, null, null, 0, IMPLIED), + attr(CODE, null, null, 0, IMPLIED), + attr(OBJECT, null, null, 0, IMPLIED), + attr(ALT, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, IMPLIED), + attr(WIDTH, null, null, 0, REQUIRED), + attr(HEIGHT, null, null, 0, REQUIRED), + attr(ALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, LEFT, RIGHT }, + 0, IMPLIED), + attr(HSPACE, null, null, 0, IMPLIED), + attr(VSPACE, null, null, 0, IMPLIED) + } + ); + defElement(AREA, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(SHAPE, RECT, new String[] { RECT, CIRCLE, POLY, DEFAULTS }, + 0, DEFAULT), + attr(COORDS, null, null, 0, IMPLIED), + attr(HREF, null, null, 0, IMPLIED), + attr(TARGET, null, null, 0, IMPLIED), + attr(NOHREF, null, new String[] { NOHREF }, 0, IMPLIED), + attr(ALT, null, null, 0, REQUIRED), + attr(TABINDEX, null, null, NUMBER, IMPLIED), + attr(ACCESSKEY, null, null, 0, IMPLIED), + attr(ONFOCUS, null, null, 0, IMPLIED), + attr(ONBLUR, null, null, 0, IMPLIED) + } + ); + defElement(B, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(BASE, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(HREF, null, null, 0, IMPLIED), + attr(TARGET, null, null, 0, IMPLIED) + } + ); + defElement(BASEFONT, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(SIZE, null, null, 0, REQUIRED), + attr(COLOR, null, null, 0, IMPLIED), + attr(FACE, null, null, 0, IMPLIED) + } + ); + defElement(BDO, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, REQUIRED) + } + ); + defElement(BIG, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(BLOCKQUOTE, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(CITE, null, null, 0, IMPLIED) + } + ); + defElement(BODY, 0, true, true, null, + NONE + , + getBodyElements() + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ONLOAD, null, null, 0, IMPLIED), + attr(ONUNLOAD, null, null, 0, IMPLIED), + attr(BACKGROUND, null, null, 0, IMPLIED), + attr(BGCOLOR, null, null, 0, IMPLIED), + attr(TEXT, null, null, 0, IMPLIED), + attr(LINK, null, null, 0, IMPLIED), + attr(VLINK, null, null, 0, IMPLIED), + attr(ALINK, null, null, 0, IMPLIED) + } + ); + defElement(BR, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(CLEAR, "NONE", new String[] { LEFT, ALL, RIGHT, NONES }, + 0, DEFAULT) + } + ); + defElement(BUTTON, 0, false, false, null, + new String[] { + A, BUTTON, IFRAME, INPUT, + LABEL, SELECT, TEXTAREA, FIELDSET, FORM, + ISINDEX + } + , + new String[] { + PCDATA, ABBR, ACRONYM, APPLET, + B, BASEFONT, BDO, BIG, BR, + CITE, CODE, DFN, EM, FONT, + I, IMG, KBD, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SMALL, + SPAN, STRIKE, STRONG, SUB, SUP, + TT, U, VAR, ADDRESS, BLOCKQUOTE, + CENTER, DIR, DIV, DL, H1, + H2, H3, H4, H5, H6, + HR, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, IMPLIED), + attr(VALUE, null, null, 0, IMPLIED), + attr(TYPE, SUBMIT, new String[] { BUTTON, SUBMIT, RESET }, 0, DEFAULT), + attr(DISABLED, null, new String[] { DISABLED }, 0, IMPLIED), + attr(TABINDEX, null, null, NUMBER, IMPLIED), + attr(ACCESSKEY, null, null, 0, IMPLIED), + attr(ONFOCUS, null, null, 0, IMPLIED), + attr(ONBLUR, null, null, 0, IMPLIED) + } + ); + defElement(CAPTION, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { TOP, BOTTOM, LEFT, RIGHT }, + 0, IMPLIED) + } + ); + + } + + /** + * Define second sixth of elements of this DTD. + */ + private void defineElements2() + { + /* Define the elements. */ + defElement(CENTER, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(CITE, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(CODE, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(COL, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(SPAN, C_1, null, NUMBER, DEFAULT), + attr(WIDTH, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY, CHAR }, + 0, IMPLIED), + attr(CHAR, null, null, 0, IMPLIED), + attr(CHAROFF, null, null, 0, IMPLIED), + attr(VALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, BASELINE }, + 0, IMPLIED) + } + ); + defElement(COLGROUP, 0, false, true, null, + NONE + , + new String[] { + COL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(SPAN, C_1, null, NUMBER, DEFAULT), + attr(WIDTH, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY, CHAR }, + 0, IMPLIED), + attr(CHAR, null, null, 0, IMPLIED), + attr(CHAROFF, null, null, 0, IMPLIED), + attr(VALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, BASELINE }, + 0, IMPLIED) + } + ); + defElement(DD, 0, false, true, new ContentModel(0, + new noTagModel( new String[] { DD, DT } ), null ), + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(DEL, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(CITE, null, null, 0, IMPLIED), + attr(DATETIME, null, null, 0, IMPLIED) + } + ); + defElement(DFN, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(DIR, 0, false, false, createListModel(), + new String[] { + ADDRESS, BLOCKQUOTE, CENTER, DIR, + DIV, DL, FIELDSET, FORM, H1, + H2, H3, H4, H5, H6, + HR, ISINDEX, MENU, NOFRAMES, NOSCRIPT, + OL, P, PRE, TABLE, UL + } + , + new String[] { + LI, UL, OL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(COMPACT, null, new String[] { COMPACT }, 0, IMPLIED) + } + ); + defElement(DIV, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY }, + 0, IMPLIED) + } + ); + defElement(DL, 0, false, false, createDefListModel(), + NONE + , + new String[] { + DD, DT + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(COMPACT, null, new String[] { COMPACT }, 0, IMPLIED) + } + ); + defElement(DT, 0, false, true, + new ContentModel(0, + new noTagModel( new String[] { DT, DD } ), null), + BLOCK + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(EM, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(FIELDSET, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL, LEGEND + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + + } + + /** + * Define third sixth of elements of this DTD. + */ + private void defineElements3() + { + /* Define the elements. */ + defElement(FONT, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(SIZE, null, null, 0, IMPLIED), + attr(COLOR, null, null, 0, IMPLIED), + attr(FACE, null, null, 0, IMPLIED) + } + ); + defElement(FORM, 0, false, false, null, + new String[] { + FORM + } + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, H1, H2, H3, + H4, H5, H6, HR, ISINDEX, + MENU, NOFRAMES, NOSCRIPT, OL, P, + PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ACTION, null, null, 0, REQUIRED), + attr(METHOD, GET, new String[] { GET, POST }, 0, DEFAULT), + attr(ENCTYPE, APPLICATION_X_WWW_FORM_URLENCODED, null, 0, DEFAULT), + attr(ACCEPT, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, IMPLIED), + attr(ONSUBMIT, null, null, 0, IMPLIED), + attr(ONRESET, null, null, 0, IMPLIED), + attr(TARGET, null, null, 0, IMPLIED), + attr(ACCEPTCHARSET, null, null, 0, IMPLIED) + } + ); + defElement(FRAME, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LONGDESC, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, IMPLIED), + attr(SRC, null, null, 0, IMPLIED), + attr(FRAMEBORDER, C_1, new String[] { C_1, C_0 }, 0, DEFAULT), + attr(MARGINWIDTH, null, null, PIXELS, IMPLIED), + attr(MARGINHEIGHT, null, null, PIXELS, IMPLIED), + attr(NORESIZE, null, new String[] { NORESIZE }, 0, IMPLIED), + attr(SCROLLING, AUTO, new String[] { YES, NO, AUTO }, 0, DEFAULT) + } + ); + defElement(FRAMESET, 0, false, false, null, + NONE + , + new String[] { + NOFRAMES, FRAME, FRAMESET + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(ROWS, null, null, 0, IMPLIED), + attr(COLS, null, null, 0, IMPLIED), + attr(ONLOAD, null, null, 0, IMPLIED), + attr(ONUNLOAD, null, null, 0, IMPLIED) + } + ); + defElement(H1, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY }, + 0, IMPLIED) + } + ); + defElement(H2, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY }, + 0, IMPLIED) + } + ); + defElement(H3, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY }, + 0, IMPLIED) + } + ); + defElement(H4, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY }, + 0, IMPLIED) + } + ); + defElement(H5, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY }, + 0, IMPLIED) + } + ); + defElement(H6, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY }, + 0, IMPLIED) + } + ); + defElement(HEAD, 0, true, true, null, + new String[] { + BODY + } + , + new String[] { + TITLE, ISINDEX, BASE, + SCRIPT, STYLE, META, LINK, OBJECT + } + , + new AttributeList[] { + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(PROFILE, null, null, 0, IMPLIED) + } + ); + + defElement(HR, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT }, 0, IMPLIED), + attr(NOSHADE, null, new String[] { NOSHADE }, 0, IMPLIED), + attr(SIZE, null, null, 0, IMPLIED), + attr(WIDTH, null, null, 0, IMPLIED) + } + ); + defElement(HTML, 0, true, true, createHtmlContentModel(), + NONE + , + new String[] { + HEAD, BODY + } + , + new AttributeList[] { + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(VERSION, DTD_NAME, null, 0, FIXED) + } + ); + defElement(I, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(IFRAME, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LONGDESC, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, IMPLIED), + attr(SRC, null, null, 0, IMPLIED), + attr(FRAMEBORDER, C_1, new String[] { C_1, C_0 }, 0, DEFAULT), + attr(MARGINWIDTH, null, null, PIXELS, IMPLIED), + attr(MARGINHEIGHT, null, null, PIXELS, IMPLIED), + attr(SCROLLING, AUTO, new String[] { YES, NO, AUTO }, 0, DEFAULT), + attr(ALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, LEFT, RIGHT }, + 0, IMPLIED), + attr(HEIGHT, null, null, 0, IMPLIED), + attr(WIDTH, null, null, 0, IMPLIED) + } + ); + defElement(IMG, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(SRC, null, null, 0, REQUIRED), + attr(ALT, null, null, 0, REQUIRED), + attr(LONGDESC, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, IMPLIED), + attr(HEIGHT, null, null, 0, IMPLIED), + attr(WIDTH, null, null, 0, IMPLIED), + attr(USEMAP, null, null, 0, IMPLIED), + attr(ISMAP, null, new String[] { ISMAP }, 0, IMPLIED), + attr(ALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, LEFT, RIGHT }, + 0, IMPLIED), + attr(BORDER, null, null, PIXELS, IMPLIED), + attr(HSPACE, null, null, 0, IMPLIED), + attr(VSPACE, null, null, 0, IMPLIED) + } + ); + + } + + /** + * Define fourth sixth of elements of this DTD. + */ + private void defineElements4() + { + /* Define the elements. */ + defElement(INPUT, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(TYPE, TEXT, new String[] { TEXT, PASSWORD, CHECKBOX, RADIO, + SUBMIT, RESET, FILE, HIDDEN, IMAGE, BUTTON }, 0, DEFAULT), + attr(sNAME, null, null, 0, IMPLIED), + attr(VALUE, null, null, 0, IMPLIED), + attr(CHECKED, null, new String[] { CHECKED }, 0, IMPLIED), + attr(DISABLED, null, new String[] { DISABLED }, 0, IMPLIED), + attr(READONLY, null, new String[] { READONLY }, 0, IMPLIED), + attr(SIZE, null, null, 0, IMPLIED), + attr(MAXLENGTH, null, null, 0, IMPLIED), + attr(SRC, null, null, 0, IMPLIED), + attr(ALT, null, null, 0, IMPLIED), + attr(USEMAP, null, null, 0, IMPLIED), + attr(ISMAP, null, new String[] { ISMAP }, 0, IMPLIED), + attr(TABINDEX, null, null, NUMBER, IMPLIED), + attr(ACCESSKEY, null, null, 0, IMPLIED), + attr(ONFOCUS, null, null, 0, IMPLIED), + attr(ONBLUR, null, null, 0, IMPLIED), + attr(ONSELECT, null, null, 0, IMPLIED), + attr(ONCHANGE, null, null, 0, IMPLIED), + attr(ACCEPT, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, LEFT, RIGHT }, + 0, IMPLIED) + } + ); + defElement(INS, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(CITE, null, null, 0, IMPLIED), + attr(DATETIME, null, null, 0, IMPLIED) + } + ); + defElement(ISINDEX, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(PROMPT, null, null, 0, IMPLIED) + } + ); + defElement(KBD, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(LABEL, 0, false, false, null, + new String[] { + LABEL + } + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, MAP, OBJECT, Q, + S, SAMP, SCRIPT, SELECT, SMALL, + SPAN, STRIKE, STRONG, SUB, SUP, + TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(FOR, null, null, 0, IMPLIED), + attr(ACCESSKEY, null, null, 0, IMPLIED), + attr(ONFOCUS, null, null, 0, IMPLIED), + attr(ONBLUR, null, null, 0, IMPLIED) + } + ); + defElement(LEGEND, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ACCESSKEY, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { TOP, BOTTOM, LEFT, RIGHT }, + 0, IMPLIED) + } + ); + // LI has a special content model that will be resolved into + // by transformer. + defElement(LI, 0, false, true, + new ContentModel(0, + new noTagModel(LI), null), + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(TYPE, null, null, 0, IMPLIED), + attr(VALUE, null, null, NUMBER, IMPLIED) + } + ); + defElement(LINK, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(CHARSET, null, null, 0, IMPLIED), + attr(HREF, null, null, 0, IMPLIED), + attr(HREFLANG, null, null, 0, IMPLIED), + attr(TYPE, null, null, 0, IMPLIED), + attr(REL, null, null, 0, IMPLIED), + attr(REV, null, null, 0, IMPLIED), + attr(MEDIA, null, null, 0, IMPLIED), + attr(TARGET, null, null, 0, IMPLIED) + } + ); + defElement(MAP, 0, false, false, null, + NONE + , + new String[] { + ADDRESS, BLOCKQUOTE, CENTER, DIR, + DIV, DL, FIELDSET, FORM, H1, + H2, H3, H4, H5, H6, + HR, ISINDEX, MENU, NOFRAMES, NOSCRIPT, + OL, P, PRE, TABLE, UL, + AREA + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, REQUIRED) + } + ); + defElement(MENU, 0, false, false, createListModel(), + new String[] { + ADDRESS, BLOCKQUOTE, CENTER, DIR, + DIV, DL, FIELDSET, FORM, H1, + H2, H3, H4, H5, H6, + HR, ISINDEX, MENU, NOFRAMES, NOSCRIPT, + OL, P, PRE, TABLE, UL + } + , + new String[] { + LI, UL, OL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(COMPACT, null, new String[] { COMPACT }, 0, IMPLIED) + } + ); + defElement(META, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(HTTPEQUIV, null, null, 0, IMPLIED), + attr(sNAME, null, null, NAME, IMPLIED), + attr(CONTENT, null, null, 0, REQUIRED), + attr(SCHEME, null, null, 0, IMPLIED) + } + ); + defElement(NOFRAMES, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(NOSCRIPT, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(OBJECT, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL, PARAM + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(DECLARE, null, new String[] { DECLARE }, 0, IMPLIED), + attr(CLASSID, null, null, 0, IMPLIED), + attr(CODEBASE, null, null, 0, IMPLIED), + attr(DATA, null, null, 0, IMPLIED), + attr(TYPE, null, null, 0, IMPLIED), + attr(CODETYPE, null, null, 0, IMPLIED), + attr(ARCHIVE, null, null, 0, IMPLIED), + attr(STANDBY, null, null, 0, IMPLIED), + attr(HEIGHT, null, null, 0, IMPLIED), + attr(WIDTH, null, null, 0, IMPLIED), + attr(USEMAP, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, IMPLIED), + attr(TABINDEX, null, null, NUMBER, IMPLIED), + attr(ALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, LEFT, RIGHT }, + 0, IMPLIED), + attr(BORDER, null, null, PIXELS, IMPLIED), + attr(HSPACE, null, null, 0, IMPLIED), + attr(VSPACE, null, null, 0, IMPLIED) + } + ); + + } + + /** + * Define fifth sixth of elements of this DTD. + */ + private void defineElements5() + { + /* Define the elements. */ + defElement(OL, 0, false, false, createListModel(), + NONE + , + new String[] { + // See note on the createListModel method + LI, UL, OL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(TYPE, null, null, 0, IMPLIED), + attr(COMPACT, null, new String[] { COMPACT }, 0, IMPLIED), + attr(START, null, null, 0, IMPLIED) + } + ); + defElement(OPTGROUP, 0, false, false, null, + NONE + , + new String[] { + OPTION + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(DISABLED, null, new String[] { DISABLED }, 0, IMPLIED), + attr(LABEL, null, null, 0, REQUIRED) + } + ); + defElement(OPTION, 0, false, true, new ContentModel(0, + new PCDATAonly_model(), null), + NONE, + new String[] { + PCDATA + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(SELECTED, null, new String[] { SELECTED }, 0, IMPLIED), + attr(DISABLED, null, new String[] { DISABLED }, 0, IMPLIED), + attr(LABEL, null, null, 0, IMPLIED), + attr(VALUE, null, null, 0, IMPLIED) + } + ); + + // Headers in the paragraph are not allowed. + defElement(P, 0, false, true, new ContentModel( 0, + new noTagModel(new String[] { P, H1, H2, H3, H4, H5, H6 }), null), + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY }, + 0, IMPLIED) + } + ); + defElement(PARAM, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(sNAME, null, null, 0, REQUIRED), + attr(VALUE, null, null, 0, IMPLIED), + attr(VALUETYPE, DATA, new String[] { DATA, REF, OBJECT }, 0, DEFAULT), + attr(TYPE, null, null, 0, IMPLIED) + } + ); + defElement(PRE, 0, false, false, null, + new String[] { + APPLET, BASEFONT, BIG, FONT, + IMG, OBJECT, SMALL, SUB, SUP + } + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + B, BDO, BR, BUTTON, CITE, + CODE, DFN, EM, I, IFRAME, + INPUT, KBD, LABEL, MAP, Q, + S, SAMP, SCRIPT, SELECT, SPAN, + STRIKE, STRONG, TEXTAREA, TT, U, + VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(WIDTH, null, null, NUMBER, IMPLIED) + } + ); + defElement(Q, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(CITE, null, null, 0, IMPLIED) + } + ); + defElement(S, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(SAMP, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(SCRIPT, CDATA, false, false, null, + NONE + , + NONE + , + new AttributeList[] { + attr(CHARSET, null, null, 0, IMPLIED), + attr(TYPE, null, null, 0, REQUIRED), + attr(LANGUAGE, null, null, 0, IMPLIED), + attr(SRC, null, null, 0, IMPLIED), + attr(DEFER, null, new String[] { DEFER }, 0, IMPLIED), + attr(EVENT, null, null, 0, IMPLIED), + attr(FOR, null, null, 0, IMPLIED) + } + ); + defElement(SELECT, 0, false, false, null, + NONE + , + new String[] { + OPTGROUP, OPTION + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, IMPLIED), + attr(SIZE, null, null, NUMBER, IMPLIED), + attr(MULTIPLE, null, new String[] { MULTIPLE }, 0, IMPLIED), + attr(DISABLED, null, new String[] { DISABLED }, 0, IMPLIED), + attr(TABINDEX, null, null, NUMBER, IMPLIED), + attr(ONFOCUS, null, null, 0, IMPLIED), + attr(ONBLUR, null, null, 0, IMPLIED), + attr(ONCHANGE, null, null, 0, IMPLIED) + } + ); + defElement(SMALL, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(SPAN, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(STRIKE, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(STRONG, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(STYLE, CDATA, false, false, null, + NONE + , + NONE + , + new AttributeList[] { + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(TYPE, null, null, 0, REQUIRED), + attr(MEDIA, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED) + } + ); + defElement(SUB, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + + } + + /** + * Define last sixth of elements of this DTD. + */ + private void defineElements6() + { + /* Define the elements. */ + defElement(SUP, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(TABLE, 0, false, false, createTableContentModel(), + NONE + , + new String[] { + CAPTION, COL, COLGROUP, TBODY, + TFOOT, THEAD + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(SUMMARY, null, null, 0, IMPLIED), + attr(WIDTH, null, null, 0, IMPLIED), + attr(BORDER, null, null, PIXELS, IMPLIED), + attr(FRAME, null, new String[] { VOID, ABOVE, BELOW, HSIDES, LHS, RHS, + VSIDES, BOX, BORDER }, 0, IMPLIED), + attr(RULES, null, new String[] { NONES, GROUPS, ROWS, COLS, ALL }, + 0, IMPLIED), + attr(CELLSPACING, null, null, 0, IMPLIED), + attr(CELLPADDING, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT }, 0, IMPLIED), + attr(BGCOLOR, null, null, 0, IMPLIED), + attr(DATAPAGESIZE, null, null, 0, IMPLIED) + } + ); + defElement(TBODY, 0, true, true, model(TR,'+'), + NONE + , + new String[] { + TR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY, CHAR }, + 0, IMPLIED), + attr(CHAR, null, null, 0, IMPLIED), + attr(CHAROFF, null, null, 0, IMPLIED), + attr(VALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, BASELINE }, + 0, IMPLIED) + } + ); + + defElement(TD, 0, false, true, + new ContentModel(0, + new noTagModel(new String[] {"TD", "TH", "TR" } ), null), + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ABBR, null, null, 0, IMPLIED), + attr(AXIS, null, null, 0, IMPLIED), + attr(HEADERS, null, null, 0, IMPLIED), + attr(SCOPE, null, new String[] { ROW, COL, ROWGROUP, COLGROUP }, + 0, IMPLIED), + attr(ROWSPAN, C_1, null, NUMBER, DEFAULT), + attr(COLSPAN, C_1, null, NUMBER, DEFAULT), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY, CHAR }, + 0, IMPLIED), + attr(CHAR, null, null, 0, IMPLIED), + attr(CHAROFF, null, null, 0, IMPLIED), + attr(VALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, BASELINE }, + 0, IMPLIED), + attr(NOWRAP, null, new String[] { NOWRAP }, 0, IMPLIED), + attr(BGCOLOR, null, null, 0, IMPLIED), + attr(WIDTH, null, null, 0, IMPLIED), + attr(HEIGHT, null, null, 0, IMPLIED) + } + ); + defElement(TEXTAREA, 0, false, false, null, + NONE + , + new String[] { + PCDATA + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, IMPLIED), + attr(ROWS, null, null, NUMBER, REQUIRED), + attr(COLS, null, null, NUMBER, REQUIRED), + attr(DISABLED, null, new String[] { DISABLED }, 0, IMPLIED), + attr(READONLY, null, new String[] { READONLY }, 0, IMPLIED), + attr(TABINDEX, null, null, NUMBER, IMPLIED), + attr(ACCESSKEY, null, null, 0, IMPLIED), + attr(ONFOCUS, null, null, 0, IMPLIED), + attr(ONBLUR, null, null, 0, IMPLIED), + attr(ONSELECT, null, null, 0, IMPLIED), + attr(ONCHANGE, null, null, 0, IMPLIED) + } + ); + defElement(TFOOT, 0, false, true, model(TR,'+'), + NONE + , + new String[] { + TR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY, CHAR }, + 0, IMPLIED), + attr(CHAR, null, null, 0, IMPLIED), + attr(CHAROFF, null, null, 0, IMPLIED), + attr(VALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, BASELINE }, + 0, IMPLIED) + } + ); + defElement(TH, 0, false, true, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ABBR, null, null, 0, IMPLIED), + attr(AXIS, null, null, 0, IMPLIED), + attr(HEADERS, null, null, 0, IMPLIED), + attr(SCOPE, null, new String[] { ROW, COL, ROWGROUP, COLGROUP }, + 0, IMPLIED), + attr(ROWSPAN, C_1, null, NUMBER, DEFAULT), + attr(COLSPAN, C_1, null, NUMBER, DEFAULT), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY, CHAR }, + 0, IMPLIED), + attr(CHAR, null, null, 0, IMPLIED), + attr(CHAROFF, null, null, 0, IMPLIED), + attr(VALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, BASELINE }, + 0, IMPLIED), + attr(NOWRAP, null, new String[] { NOWRAP }, 0, IMPLIED), + attr(BGCOLOR, null, null, 0, IMPLIED), + attr(WIDTH, null, null, 0, IMPLIED), + attr(HEIGHT, null, null, 0, IMPLIED) + } + ); + defElement(THEAD, 0, false, true, model(TR,'+'), + NONE + , + new String[] { + TR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY, CHAR }, + 0, IMPLIED), + attr(CHAR, null, null, 0, IMPLIED), + attr(CHAROFF, null, null, 0, IMPLIED), + attr(VALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, BASELINE }, + 0, IMPLIED) + } + ); + defElement(TITLE, 0, false, false, null, + new String[] { + OBJECT, SCRIPT, LINK, META, + STYLE + } + , + new String[] { + PCDATA + } + , + new AttributeList[] { + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED) + } + ); + defElement(TR, 0, false, true, + new ContentModel(0, new TableRowContentModel(this), null), + NONE + , + new String[] { + TD, TH + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY, CHAR }, + 0, IMPLIED), + attr(CHAR, null, null, 0, IMPLIED), + attr(CHAROFF, null, null, 0, IMPLIED), + attr(VALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, BASELINE }, + 0, IMPLIED), + attr(BGCOLOR, null, null, 0, IMPLIED) + } + ); + defElement(TT, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(U, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(UL, 0, false, false, createListModel(), + NONE + , + new String[] { + // See note on the createListModel method + LI, UL, OL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(TYPE, null, new String[] { DISC, SQUARE, CIRCLE }, 0, IMPLIED), + attr(COMPACT, null, new String[] { COMPACT }, 0, IMPLIED) + } + ); + defElement(VAR, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + + } + + /** + * Define all entities in this DTD. + */ + protected void defineEntities() + { + /* Define general entities */ + defineEntity("AElig", 198); + defineEntity("Aacute", 193); + defineEntity("Acirc", 194); + defineEntity("Agrave", 192); + defineEntity("Alpha", 913); + defineEntity("Aring", 197); + defineEntity("Atilde", 195); + defineEntity("Auml", 196); + defineEntity("Beta", 914); + defineEntity("Ccedil", 199); + defineEntity("Chi", 935); + defineEntity("Dagger", 8225); + defineEntity("Delta", 916); + defineEntity("ETH", 208); + defineEntity("Eacute", 201); + defineEntity("Ecirc", 202); + defineEntity("Egrave", 200); + defineEntity("Epsilon", 917); + defineEntity("Eta", 919); + defineEntity("Euml", 203); + defineEntity("Gamma", 915); + defineEntity("Iacute", 205); + defineEntity("Icirc", 206); + defineEntity("Igrave", 204); + defineEntity("Iota", 921); + defineEntity("Iuml", 207); + defineEntity("Kappa", 922); + defineEntity("Lambda", 923); + defineEntity("Mu", 924); + defineEntity("Ntilde", 209); + defineEntity("Nu", 925); + defineEntity("OElig", 338); + defineEntity("Oacute", 211); + defineEntity("Ocirc", 212); + defineEntity("Ograve", 210); + defineEntity("Omega", 937); + defineEntity("Omicron", 927); + defineEntity("Oslash", 216); + defineEntity("Otilde", 213); + defineEntity("Ouml", 214); + defineEntity("Phi", 934); + defineEntity("Pi", 928); + defineEntity("Prime", 8243); + defineEntity("Psi", 936); + defineEntity("Rho", 929); + defineEntity("Scaron", 352); + defineEntity("Sigma", 931); + defineEntity("THORN", 222); + defineEntity("Tau", 932); + defineEntity("Theta", 920); + defineEntity("Uacute", 218); + defineEntity("Ucirc", 219); + defineEntity("Ugrave", 217); + defineEntity("Upsilon", 933); + defineEntity("Uuml", 220); + defineEntity("Xi", 926); + defineEntity("Yacute", 221); + defineEntity("Yuml", 376); + defineEntity("Zeta", 918); + defineEntity("aacute", 225); + defineEntity("acirc", 226); + defineEntity("acute", 180); + defineEntity("aelig", 230); + defineEntity("agrave", 224); + defineEntity("alefsym", 8501); + defineEntity("alpha", 945); + defineEntity("amp", 38); + defineEntity("and", 8743); + defineEntity("ang", 8736); + defineEntity("aring", 229); + defineEntity("asymp", 8776); + defineEntity("atilde", 227); + defineEntity("auml", 228); + defineEntity("bdquo", 8222); + defineEntity("beta", 946); + defineEntity("brvbar", 166); + defineEntity("bull", 8226); + defineEntity("cap", 8745); + defineEntity("ccedil", 231); + defineEntity("cedil", 184); + defineEntity("cent", 162); + defineEntity("chi", 967); + defineEntity("circ", 710); + defineEntity("clubs", 9827); + defineEntity("cong", 8773); + defineEntity("copy", 169); + defineEntity("crarr", 8629); + defineEntity("cup", 8746); + defineEntity("curren", 164); + defineEntity("dArr", 8659); + defineEntity("dagger", 8224); + defineEntity("darr", 8595); + defineEntity("deg", 176); + defineEntity("delta", 948); + defineEntity("diams", 9830); + defineEntity("divide", 247); + defineEntity("eacute", 233); + defineEntity("ecirc", 234); + defineEntity("egrave", 232); + defineEntity("empty", 8709); + defineEntity("emsp", 8195); + defineEntity("ensp", 8194); + defineEntity("epsilon", 949); + defineEntity("equiv", 8801); + defineEntity("eta", 951); + defineEntity("eth", 240); + defineEntity("euml", 235); + defineEntity("euro", 8364); + defineEntity("exist", 8707); + defineEntity("fnof", 402); + defineEntity("forall", 8704); + defineEntity("frac12", 189); + defineEntity("frac14", 188); + defineEntity("frac34", 190); + defineEntity("frasl", 8260); + defineEntity("gamma", 947); + defineEntity("ge", 8805); + defineEntity("gt", 62); + defineEntity("hArr", 8660); + defineEntity("harr", 8596); + defineEntity("hearts", 9829); + defineEntity("hellip", 8230); + defineEntity("iacute", 237); + defineEntity("icirc", 238); + defineEntity("iexcl", 161); + defineEntity("igrave", 236); + defineEntity("image", 8465); + defineEntity("infin", 8734); + defineEntity("int", 8747); + defineEntity("iota", 953); + defineEntity("iquest", 191); + defineEntity("isin", 8712); + defineEntity("iuml", 239); + defineEntity("kappa", 954); + defineEntity("lArr", 8656); + defineEntity("lambda", 955); + defineEntity("lang", 9001); + defineEntity("laquo", 171); + defineEntity("larr", 8592); + defineEntity("lceil", 8968); + defineEntity("ldquo", 8220); + defineEntity("le", 8804); + defineEntity("lfloor", 8970); + defineEntity("lowast", 8727); + defineEntity("loz", 9674); + defineEntity("lrm", 8206); + defineEntity("lsaquo", 8249); + defineEntity("lsquo", 8216); + defineEntity("lt", 60); + defineEntity("macr", 175); + defineEntity("mdash", 8212); + defineEntity("micro", 181); + defineEntity("middot", 183); + defineEntity("minus", 8722); + defineEntity("mu", 956); + defineEntity("nabla", 8711); + defineEntity("nbsp", 160); + defineEntity("ndash", 8211); + defineEntity("ne", 8800); + defineEntity("ni", 8715); + defineEntity("not", 172); + defineEntity("notin", 8713); + defineEntity("nsub", 8836); + defineEntity("ntilde", 241); + defineEntity("nu", 957); + defineEntity("oacute", 243); + defineEntity("ocirc", 244); + defineEntity("oelig", 339); + defineEntity("ograve", 242); + defineEntity("oline", 8254); + defineEntity("omega", 969); + defineEntity("omicron", 959); + defineEntity("oplus", 8853); + defineEntity("or", 8744); + defineEntity("ordf", 170); + defineEntity("ordm", 186); + defineEntity("oslash", 248); + defineEntity("otilde", 245); + defineEntity("otimes", 8855); + defineEntity("ouml", 246); + defineEntity("para", 182); + defineEntity("part", 8706); + defineEntity("permil", 8240); + defineEntity("perp", 8869); + defineEntity("phi", 966); + defineEntity("pi", 960); + defineEntity("piv", 982); + defineEntity("plusmn", 177); + defineEntity("pound", 163); + defineEntity("prime", 8242); + defineEntity("prod", 8719); + defineEntity("prop", 8733); + defineEntity("psi", 968); + defineEntity("quot", 34); + defineEntity("rArr", 8658); + defineEntity("radic", 8730); + defineEntity("rang", 9002); + defineEntity("raquo", 187); + defineEntity("rarr", 8594); + defineEntity("rceil", 8969); + defineEntity("rdquo", 8221); + defineEntity("real", 8476); + defineEntity("reg", 174); + defineEntity("rfloor", 8971); + defineEntity("rho", 961); + defineEntity("rlm", 8207); + defineEntity("rsaquo", 8250); + defineEntity("rsquo", 8217); + defineEntity("sbquo", 8218); + defineEntity("scaron", 353); + defineEntity("sdot", 8901); + defineEntity("sect", 167); + defineEntity("shy", 173); + defineEntity("sigma", 963); + defineEntity("sigmaf", 962); + defineEntity("sim", 8764); + defineEntity("spades", 9824); + defineEntity("sub", 8834); + defineEntity("sube", 8838); + defineEntity("sum", 8721); + defineEntity("sup", 8835); + defineEntity("sup1", 185); + defineEntity("sup2", 178); + defineEntity("sup3", 179); + defineEntity("supe", 8839); + defineEntity("szlig", 223); + defineEntity("tau", 964); + defineEntity("there4", 8756); + defineEntity("theta", 952); + defineEntity("thetasym", 977); + defineEntity("thinsp", 8201); + defineEntity("thorn", 254); + defineEntity("tilde", 732); + defineEntity("times", 215); + defineEntity("trade", 8482); + defineEntity("uArr", 8657); + defineEntity("uacute", 250); + defineEntity("uarr", 8593); + defineEntity("ucirc", 251); + defineEntity("ugrave", 249); + defineEntity("uml", 168); + defineEntity("upsih", 978); + defineEntity("upsilon", 965); + defineEntity("uuml", 252); + defineEntity("weierp", 8472); + defineEntity("xi", 958); + defineEntity("yacute", 253); + defineEntity("yen", 165); + defineEntity("yuml", 255); + defineEntity("zeta", 950); + defineEntity("zwj", 8205); + defineEntity("zwnj", 8204); + } + + /** + * Crate a content model, consisting of the single + * element, specified by name. + */ + protected ContentModel model(String element) + { + return new ContentModel(getElement(element)); + } + + /** + * Crate a chain from the two content models, + * the last containing the given element and + * the specified unary operation. + */ + private ContentModel model(String element, int unary) + { + ContentModel ct = model(element); + ct.type = unary; + return new ContentModel(0, ct); + } + + /** + * Create the model HEAD, BODY + * @return the HTML content model of the whole document + */ + protected ContentModel createHtmlContentModel() + { + ContentModel head = model(HEAD); + ContentModel body = model(BODY); + head.next = body; + head.type = ','; + return head; + } + + /** + * Create the model + * ( CAPTION ? , ( COL * | COLGROUP * ) , THEAD ? , TFOOT ? , TBODY + ) + */ + protected ContentModel createTableContentModel() + { + ContentModel col_colgroup = new ContentModel + ('|', model(COL,'*'), model(COLGROUP,'*') ); + + col_colgroup = new ContentModel('*', col_colgroup); + col_colgroup = new ContentModel(',', col_colgroup); + + ContentModel caption = model(CAPTION,'?'); + ContentModel thead = model(THEAD, '?'); + ContentModel tfoot = model(TFOOT, '?'); + ContentModel tbody = model(TBODY, '+'); + + caption.next = col_colgroup; + col_colgroup.next = thead; + thead.next = tfoot; + tfoot.next = tbody; + + caption.type = col_colgroup.type = thead.type = tfoot.type = + tbody.type = ','; + + return caption; + } + + /** + * Creates a model for <DL> tag: + * DT+ | DL+ . + * @return + */ + protected ContentModel createDefListModel() + { + ContentModel dt = model(DT, '+'); + ContentModel dd = model(DD, '+'); + + dt.next = dd; + dt.type = dd.type = '|'; + return dt; + } + + /** + * This model is used for UL, OL, MENU and DIR. + * HTML 4.01 specifies LI only, but the nested + * list seems rendered correctly only if + * it is not enclosed into
  • -
  • of the + * parent list. + */ + protected ContentModel createListModel() + { + ContentModel li = model(LI, '+'); + ContentModel ul = model(UL, '+'); + ContentModel ol = model(OL, '+'); + + li.next = ul; + ul.next = ol; + li.type = ul.type = ol.type = '|'; + return li; + } + + /** + * Get elements that are allowed in the document body, at the zero level. + */ + protected String[] getBodyElements() + { + return new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DEL, DIR, + DIV, DL, FIELDSET, FORM, H1, + H2, H3, H4, H5, H6, + HR, INS, ISINDEX, MENU, NOFRAMES, + NOSCRIPT, OL, P, PRE, TABLE, + UL + }; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/SmallHtmlAttributeSet.java b/libjava/classpath/gnu/javax/swing/text/html/parser/SmallHtmlAttributeSet.java new file mode 100644 index 000000000..8739ad453 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/SmallHtmlAttributeSet.java @@ -0,0 +1,261 @@ +/* SmallHtmlAttributeSet.java -- Small fixed HTML attribute set + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.parser; + +import java.io.Serializable; +import java.util.Enumeration; +import java.util.NoSuchElementException; + +import javax.swing.text.AttributeSet; +import javax.swing.text.html.HTML.Attribute; +import javax.swing.text.html.HTML.Tag; + +/** + * Small fixed HTML attribute set. The most of the HTML elements contain only + * several attributes. With four attributes, the number of operations in more + * complex algorithms is not larger than using the naive algorithm. + * + * Same as HtmlAttributeSet, this set allows both strings and non-string as + * keys. The strings are case insensitive, the non strings are compared with + * .equals. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class SmallHtmlAttributeSet + implements AttributeSet, Cloneable, Serializable +{ + private static final long serialVersionUID = 1; + + /** + * The keys, stored in this attribute set. + */ + final Object[] keys; + + /** + * The values, stored in this attribute set. + */ + final Object[] values; + + /** + * The parent, used for resolving the values, not found in this set. + */ + final AttributeSet parent; + + /** + * Create a new small fixed attribute set that contains the unchangeable copy + * of the passed attribute set and inherits its parent. + * + * @param copyFrom the attribute set, containing the attribute values to copy. + */ + public SmallHtmlAttributeSet(AttributeSet copyFrom) + { + int n = copyFrom.getAttributeCount(); + + keys = new Object[n]; + values = new Object[n]; + parent = copyFrom.getResolveParent(); + + Enumeration en = copyFrom.getAttributeNames(); + Object key; + Object value; + + for (int i = 0; i < n; i++) + { + key = en.nextElement(); + keys[i] = key; + value = copyFrom.getAttribute(key); + values[i] = value; + } + } + + public boolean containsAttribute(Object name, Object value) + { + Object contains = getAttribute(name); + if (value == null) + return value == contains; + else + return value.equals(contains); + } + + public boolean containsAttributes(AttributeSet attributes) + { + if (attributes == this) + return true; + Object v; + for (int i = 0; i < keys.length; i++) + { + v = attributes.getAttribute(keys[i]); + if (v != values[i]) + { + if (values[i] == null) + return false; + else if (! values[i].equals(v)) + return false; + } + } + return true; + } + + /** + * THIS can be safely returned as the set is not mutable. + */ + public AttributeSet copyAttributes() + { + return this; + } + + /** + * Get the attribute value, matching this key. If not found in this set, the + * call is delegated to parent. + * + * @return the value, matching key (or null if none). + */ + public Object getAttribute(Object key) + { + // Null and HTML attributes or tags can be searched by direct comparison. + if (key == null || key instanceof Attribute || key instanceof Tag) + { + for (int i = 0; i < keys.length; i++) + { + if (keys[i] == key) + return values[i]; + } + } + + // Strings are case insensitive. Only string can be match the string. + else if (key instanceof String) + { + String ks = (String) key; + for (int i = 0; i < keys.length; i++) + { + if (keys[i] instanceof String) + if (ks.equalsIgnoreCase((String) keys[i])) + return values[i]; + } + } + + // Otherwise, defaults to .equals + else + { + for (int i = 0; i < keys.length; i++) + { + if (key.equals(keys[i])) + return values[i]; + } + } + + if (parent != null) + return parent.getAttribute(key); + else + return null; + } + + /** + * Get the number of the stored attributes. + */ + public int getAttributeCount() + { + return keys.length; + } + + /** + * Get enumeration, containing the attribute names. No guard agains the + * concurent modification is required as the set is not mutable. + */ + public Enumeration getAttributeNames() + { + return new Enumeration() + { + int p = 0; + + public boolean hasMoreElements() + { + return p < keys.length; + } + + public Object nextElement() + { + if (p < keys.length) + return keys[p++]; + else + throw new NoSuchElementException(); + } + }; + } + + /** + * Get the parent that this set uses to resolve the not found attributes. + */ + public AttributeSet getResolveParent() + { + return parent; + } + + /** + * Check if the given attribute is defined in this set (not in the parent). + */ + public boolean isDefined(Object attrName) + { + if (attrName instanceof String) + attrName = ((String) attrName).toLowerCase(); + + for (int i = 0; i < keys.length; i++) + { + if (attrName.equals(keys[i])) + return true; + } + return false; + } + + /** + * Check this set and another set for equality by content. + */ + public boolean isEqual(AttributeSet attr) + { + return keys.length == attr.getAttributeCount() && containsAttributes(attr); + } + + /** + * It is safe to return THIS on cloning, if one happens. + */ + protected Object clone() + { + return this; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/gnuDTD.java b/libjava/classpath/gnu/javax/swing/text/html/parser/gnuDTD.java new file mode 100644 index 000000000..5924e0fb9 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/gnuDTD.java @@ -0,0 +1,421 @@ +/* gnuDTD.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.parser; + +import java.io.PrintStream; +import java.io.Serializable; + +import java.util.BitSet; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.Vector; + +import javax.swing.text.html.parser.AttributeList; +import javax.swing.text.html.parser.ContentModel; +import javax.swing.text.html.parser.Element; +import javax.swing.text.html.parser.Entity; + +/** + *

    + * The class is derived from {@link gnu.javax.swing.text.html.parser.DTD } + * making structure creation methods public. This is required when + * creating the DTD by SGML parser that must have access to the structure. + * + * SGML DTD representation. Provides basis for describing a syntax of the + * HTML documents. The fields of this class are NOT initialized in + * constructor. You need to do this separately before passing this data + * structure to the parser constructor.

    + * + *

    This implementation also provides you the derived class + * gnu.javax.swing.text.html.parser.DTD.HTML_4_0_1, where + * all fields are initialized to the values, representing HTML 4.01 + * ("-//W3C//DTD HTML 4.01 Frameset//EN") DTD. You can use it if you do not care + * about the portability between different implementations of the core + * class libraries.

    + *

    Use {@link javax.swing.HTML.HTMLEditorKit.Parser#parse } + * for parsing in accordance with "-//W3C//DTD HTML 4.01 Frameset//EN" + * without specifying DTD separately.

    + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuDTD + extends javax.swing.text.html.parser.DTD + implements javax.swing.text.html.parser.DTDConstants, Serializable +{ + /* The undocumented element types, used to specify types, not defined + in DTDConstants. */ + + /** + * The URI element type (not defined in DTDConstants). + */ + public static final int URI = 512; + + /** + * The Length element type + */ + public static final int Length = 513; + + /** + * The Char element type + */ + public static final int Char = 514; + + /** + * The Color element type + */ + public static final int Color = 515; + + /** + * Creates a new instance of gnuDTD. + * @param name the name of the DTD. + */ + public gnuDTD(String name) + { + super(name); + } + + /** + * Creates and returns new attribute (not an attribute list). + * @param name the name of this attribute + * @param type the type of this attribute (FIXED, IMPLIED or + * REQUIRED from DTDConstants). + * @param modifier the modifier of this attribute + * @param default_value the default value of this attribute or null if + * it is not specified. + * @param allowed_values the allowed values of this attribute. The multiple + * possible values in this parameter are supposed to be separated by + * '|', same as in SGML DTD <!ATTLIST tag. This parameter + * can be null if no list of allowed values is specified. + * @param atts the previous attribute of this element. This is + * placed to the field + * {@link javax.swing.text.html.parser.AttributeList#next }, + * creating a linked list. + * @return + */ + public AttributeList defAttributeList(String name, int type, int modifier, + String default_value, + String allowed_values, + AttributeList atts + ) + { + return super.defAttributeList(name, type, modifier, default_value, + allowed_values, atts + ); + } + + /** + * Define the attributes for the element with the given name. + * If the element is not exist, it is created. This method is + * needed if the element attributes are defined befor the + * element itself. + * @param forElement + * @param attributes + */ + public void defAttrsFor(String forElement, AttributeList attributes) + { + super.defineAttributes(forElement, attributes); + } + + /** + * Creates a new content model. + * @param type specifies the BNF operation for this content model. + * The valid operations are documented in the + * {@link javax.swing.text.html.parser.ContentModel#type }. + * @param content the content of this content model + * @param next if the content model is specified by BNF-like + * expression, contains the rest of this expression. + * @return The newly created content model. + */ + public ContentModel defContentModel(int type, Object content, + ContentModel next + ) + { + return super.defContentModel(type, content, next); + } + + /** + * Defines a new element and adds it to the element table. + * If the element alredy exists, + * overrides it settings with the specified values. + * @param name the name of the new element + * @param type the type of the element + * @param headless true if the element needs no starting tag + * @param tailless true if the element needs no closing tag + * @param content the element content. + * @param exclusions the elements that must be excluded from the + * content of this element, in all levels of the hierarchy. + * @param inclusions the elements that can be included as the + * content of this element. + * @param attributes the element attributes. + * @return the created or updated element. + */ + public Element defElement(String name, int type, boolean headless, + boolean tailless, ContentModel content, + String[] exclusions, String[] inclusions, + AttributeList attributes + ) + { + return super.defElement(name, type, headless, tailless, content, + exclusions, inclusions, attributes + ); + } + + /** + * Defines a new element and adds it to the element table. + * If the element alredy exists, + * overrides it settings with the specified values. + * @param name the name of the new element + * @param type the type of the element + * @param headless true if the element needs no starting tag + * @param tailless true if the element needs no closing tag + * @param content the element content. + * @param exclusions the elements that must be excluded from the + * content of this element, in all levels of the hierarchy. + * @param inclusions the elements that can be included as the + * content of this element. + * @param attributes the element attributes. + * @return the created or updated element. + */ + public Element defElement(String name, int type, boolean headless, + boolean tailless, ContentModel content, + Collection exclusions, Collection inclusions, + AttributeList attributes + ) + { + return super.defElement(name, type, headless, tailless, content, + toStringArray(exclusions), + toStringArray(inclusions), attributes + ); + } + + /** + * Defines a new element and adds it to the element table. + * If the element alredy exists, + * overrides it settings with the specified values. + * @param name the name of the new element + * @param type the type of the element + * @param headless true if the element needs no starting tag + * @param tailless true if the element needs no closing tag + * @param content the element content. + * @param exclusions the elements that must be excluded from the + * content of this element, in all levels of the hierarchy. + * @param inclusions the elements that can be included as the + * content of this element. + * @param attributes the element attributes (an array and not a + * linked list). The attributes are chained into the linked list + * inside this method. + * @return the created or updated element. + */ + public Element defElement(String name, int type, boolean headless, + boolean tailless, ContentModel content, + String[] exclusions, String[] inclusions, + AttributeList[] attributes + ) + { + AttributeList list; + + if (attributes == null || attributes.length == 0) + list = null; + else + { + if (attributes.length > 1) + for (int i = 1; i < attributes.length; i++) + { + attributes [ i - 1 ].next = attributes [ i ]; + } + list = attributes [ 0 ]; + } + + Element e = + super.defElement(name, type, headless, tailless, content, exclusions, + inclusions, list + ); + return e; + } + + /** + * Creates, adds into the internal table and returns the + * character entity like &lt; + * (means '<' ); + * This method inactivates the recursive refenrences to the same + * entity. + * @param name The entity name (without heading & and closing ;) + * @param type The entity type + * @param character The entity value (single character) + * @return The created entity + */ + public Entity defEntity(String name, int type, String data) + { + int r; + String eref = "%" + name + ";"; + do + { + r = data.indexOf(eref); + if (r > 0) + { + data = data.substring(0, r) + data.substring(r + 1); + } + } + while (r > 0); + + return super.defEntity(name, type, data); + } + + /** + * Summarises the document content into the given PrintStream. + */ + public void dump(PrintStream p) + { + Iterator iter = entityHash.entrySet().iterator(); + while (iter.hasNext()) + { + Map.Entry item = (Map.Entry) iter.next(); + Entity e = (Entity) item.getValue(); + if (e.isGeneral()) + p.println("Entity " + e.getName() + ": " + e.getString()); + } + + iter = elementHash.entrySet().iterator(); + while (iter.hasNext()) + { + Map.Entry item = (Map.Entry) iter.next(); + Element e = (Element) item.getValue(); + p.println("Element " + e.getName()); + + System.out.println(" includes:"); + dump(e.inclusions); + System.out.println(" excludes:"); + dump(e.exclusions); + System.out.println(" attributes:"); + + AttributeList atts = e.atts; + while (atts != null) + { + p.print(" " + atts.name + " = " + atts.value); + if (atts.values == null || atts.values.size() == 0) + p.println(); + else + { + Iterator viter = atts.values.iterator(); + System.out.print(" ( "); + while (viter.hasNext()) + { + System.out.print(viter.next()); + if (viter.hasNext()) + System.out.print(" | "); + } + System.out.println(" ) "); + } + atts = atts.next; + } + } + } + + /** + * Prints the content of the given attribute set to the System.out. + * @param b + */ + public void dump(BitSet b) + { + if (b != null) + { + for (int i = 0; i < b.size(); i++) + { + if (b.get(i)) + System.out.println(" " + elements.get(i)); + } + } + else + System.out.println(" NULL set"); + } + + /** + * Creates the attribute. + * @param name The attribute name. + * @param type The attribute type. + * @param modifier The attribute modifier. + * @param defaultValue Default value (or null) + * @param allowed_values Allowed values (or null) + * @return The newly created AttributeList. The next + * field is initialized to null. + */ + protected AttributeList attr(String name, String default_value, + String[] allowed_values, int type, int modifier + ) + { + Vector allowed = null; + + if (allowed_values != null) + { + allowed = new Vector(allowed_values.length); + for (int i = 0; i < allowed_values.length; i++) + { + allowed.add(allowed_values [ i ]); + } + } + + AttributeList attr = + new AttributeList(name, type, modifier, default_value, allowed, null); + + return attr; + } + + /** + * Define the general entity, holding a single character. + * @param name The entity name (for example, 'amp'). + * The defined entity is stored into the entity table. + * @param character The entity character (for example, '&'). + */ + protected void defineEntity(String name, int character) + { + super.defEntity(name, GENERAL, character); + } + + private String[] toStringArray(Collection c) + { + String[] s = new String[ c.size() ]; + Iterator iter = c.iterator(); + for (int i = 0; i < s.length; i++) + { + s [ i ] = iter.next().toString(); + } + return s; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/htmlAttributeSet.java b/libjava/classpath/gnu/javax/swing/text/html/parser/htmlAttributeSet.java new file mode 100644 index 000000000..7eb0f616e --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/htmlAttributeSet.java @@ -0,0 +1,183 @@ +/* htmlAttributeSet.java -- A set to store HTML attributes + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.parser; + +import java.util.Enumeration; + +import javax.swing.text.AttributeSet; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.html.HTML; + +/** + * A set, adapted to store HTML attributes. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class htmlAttributeSet + extends SimpleAttributeSet +{ + public static final htmlAttributeSet EMPTY_HTML_ATTRIBUTE_SET = + new htmlAttributeSet(); + + AttributeSet parent; + + /** + * Looks in this set and, if not found, later looks in the parent set. Calls + * toString(), allowing to pass as HTML.Attribute, as String to this method. + * + * @param _key A key to search for a value. + * @return The value, if one is defined. + */ + public Object getAttribute(Object _key) + { + Object v = super.getAttribute(_key); + if (v != null || _key == null) + return v; + + Object key = _key.toString().toLowerCase(); + + v = super.getAttribute(key); + if (v != null) + return v; + + key = HTML.getAttributeKey((String) key); + v = super.getAttribute(key); + if (v != null) + return v; + + if (parent != null) + return parent.getAttribute(key); + else + return null; + } + + /** + * The name set must return HTML.Attribute and not a string, + * where applicable. + */ + public Enumeration getAttributeNames() + { + // Replace the string keys by HTML.attribute, where applicable + final Enumeration enumeration = super.getAttributeNames(); + + return new Enumeration() + { + public boolean hasMoreElements() + { + return enumeration.hasMoreElements(); + } + + public Object nextElement() + { + Object key = enumeration.nextElement(); + if (key instanceof String) + { + HTML.Attribute hKey = HTML.getAttributeKey((String) key); + if (hKey != null) + return hKey; + } + return key; + } + }; + } + + /** + * Set the parent set, containing the default values. + * + * @param a_parent + */ + public void setResolveParent(AttributeSet a_parent) + { + parent = a_parent; + } + + /** + * Get the parent set, containing the default values. + * + * @return the parent, used to resolve the attributes. + */ + public AttributeSet getResolveParent() + { + return parent; + } + + /** + * Add the attribute to this attribute set. + * + * @param key Attribute key (if string, it will be case insensitive) + * @param value Attribute value + */ + public void addAttribute(Object key, Object value) + { + if (key instanceof String) + super.addAttribute(((String) key).toLowerCase(), value); + else + super.addAttribute(key, value); + } + + /** + * Copy attributes. The returned copy does not longer contains the extended + * features, needed to participate in the HTML parsing. The returned set may + * not be mutable. + */ + public AttributeSet copyAttributes() + { + if (getAttributeCount() <= 8) + // For the small size, typical in HTML tags, the direct iteration is + // faster than more complex algorithms. + return new SmallHtmlAttributeSet(this); + else + return (AttributeSet) clone(); + } + + /** + * Returns a clone of the attribute set. + * + * @return A clone of the attribute set. + */ + public Object clone() + { + htmlAttributeSet set = new htmlAttributeSet(); + set.addAttributes(this); + AttributeSet parent = getResolveParent(); + if (parent != null) + set.setResolveParent(parent); + return set; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/htmlValidator.java b/libjava/classpath/gnu/javax/swing/text/html/parser/htmlValidator.java new file mode 100644 index 000000000..2b624cc3c --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/htmlValidator.java @@ -0,0 +1,622 @@ +/* tagStack.java -- The HTML tag stack. + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.parser; + +import gnu.java.lang.CPStringBuilder; + +import gnu.javax.swing.text.html.parser.models.node; +import gnu.javax.swing.text.html.parser.models.transformer; + +import java.util.BitSet; +import java.util.Enumeration; +import java.util.LinkedList; +import java.util.ListIterator; + +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.html.HTML; +import javax.swing.text.html.parser.*; + +/** + *

    The HTML content validator, is responsible for opening and + * closing elements with optional start/end tags, detecting + * the wrongly placed html tags and reporting errors. The working instance + * is the inner class inside the {@link javax.swing.text.html.parser.Parser } + *

    + *

    This class could potentially + * provide basis for automated closing and insertion of the html tags, + * correcting the found html errors. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public abstract class htmlValidator +{ + /** + * The tag reference, holding additional information that the tag + * has been forcibly closed. + */ + protected class hTag + { + protected final Element element; + protected final HTML.Tag tag; + protected final TagElement tgElement; + protected boolean forcibly_closed; + protected node validationTrace; + + protected hTag(TagElement an_element) + { + element = an_element.getElement(); + tag = an_element.getHTMLTag(); + tgElement = an_element; + + if (element.content != null) + validationTrace = transformer.transform(element.content, dtd); + } + + /** + * This is called when the tag must be forcibly closed because + * it would make the newly appearing tag invalid. + * The parser is not notified about such event (just the error + * is reported). For such tags, the closing message does not + * appear when later reaching the end of stream. The exception is + * the <head> tag: the parser is notified about its silent closing + * when <body> or other html content appears. + */ + protected void forciblyCloseDueContext() + { + forcibly_closed = true; + } + + /** + * This is called when the tag must be forcibly closed after + * reaching the end of stream. The parser is notified as if + * closing the tag explicitly. + */ + protected void forciblyCloseDueEndOfStream() + { + forcibly_closed = true; + handleSupposedEndTag(element); + } + } + + /** + * The DTD, providing information about the valid document structure. + */ + protected final DTD dtd; + + /** + * The stack, holding the current tag context. + */ + protected final LinkedList stack = new LinkedList(); + + /** + * Creates a new tag stack, using the given DTD. + * @param a_dtd A DTD, providing the information about the valid + * tag content. + */ + public htmlValidator(DTD a_dtd) + { + dtd = a_dtd; + } + + /** + * Close all opened tags (called at the end of parsing). + */ + public void closeAll() + { + hTag h; + while (!stack.isEmpty()) + { + h = (hTag) stack.getLast(); + if (!h.forcibly_closed && !h.element.omitEnd()) + s_error("Unclosed <" + h.tag + ">, closing at the end of stream"); + + handleSupposedEndTag(h.element); + + closeTag(h.tgElement); + } + } + + /** + * Remove the given tag from the stack or (if found) from the list + * of the forcibly closed tags. + */ + public boolean closeTag(TagElement tElement) + { + HTML.Tag tag = tElement.getHTMLTag(); + hTag x; + hTag close; + + if (!stack.isEmpty()) + { + ListIterator iter = stack.listIterator(stack.size()); + + while (iter.hasPrevious()) + { + x = (hTag) iter.previous(); + if (tag.equals(x.tag)) + { + if (x.forcibly_closed && !x.element.omitEnd()) + s_error("The tag <" + x.tag + + "> has already been forcibly closed" + ); + + + // If the tag has a content model defined, forcibly close all + // tags that were opened after the tag being currently closed. + closing: + if (x.element.content != null) + { + iter = stack.listIterator(stack.size()); + while (iter.hasPrevious()) + { + close = (hTag) iter.previous(); + if (close == x) + break closing; + handleSupposedEndTag(close.element); + iter.remove(); + } + } + + stack.remove(x); + return true; + } + } + } + s_error("Closing unopened <" + tag + ">"); + return false; + } + + /** + * Add the given HTML tag to the stack of the opened tags. Forcibly closes + * all tags in the stack that does not allow this tag in they content (error + * is reported). + * @param element + */ + public void openTag(TagElement tElement, htmlAttributeSet parameters) + { + // If this is a fictional call, the message from the parser + // has recursively returned - ignore. + if (tElement.fictional()) + return; + + validateParameters(tElement, parameters); + + // If the stack is empty, start from HTML + if (stack.isEmpty() && tElement.getHTMLTag() != HTML.Tag.HTML) + { + Element html = dtd.getElement(HTML.Tag.HTML.toString()); + openFictionalTag(html); + } + + Object v = tagIsValidForContext(tElement); + if (v != Boolean.TRUE) + { + // The tag is not valid for context, the content + // model suggest to open another tag. + if (v instanceof Element) + { + int n = 0; + while (v instanceof Element && (n++ < 100)) + { + Element fe = (Element) v; + + // notify the content model that we add the proposed tag + node ccm = getCurrentContentModel(); + if (ccm != null) + ccm.show(fe); + openFictionalTag(fe); + + Object vv = tagIsValidForContext(tElement); + if (vv instanceof Element) // One level of nesting is supported. + { + openFictionalTag((Element) vv); + + Object vx = tagIsValidForContext(tElement); + if (vx instanceof Element) + openFictionalTag((Element) vx); + } + else if (vv == Boolean.FALSE) + { + // The tag is still not valid for the current + // content after opening a fictional element. + if (fe.omitEnd()) + { + // close the previously opened fictional tag. + closeLast(); + vv = tagIsValidForContext(tElement); + if (vv instanceof Element) + + // another tag was suggested by the content model + openFictionalTag((Element) vv); + } + } + v = tagIsValidForContext(tElement); + } + } + else // If the current element has the optional end tag, close it. + { + if (!stack.isEmpty()) + { + closing: + do + { + hTag last = (hTag) stack.getLast(); + if (last.element.omitEnd()) + { + closeLast(); + v = tagIsValidForContext(tElement); + if (v instanceof Element) // another tag was suggested by the content model + { + openFictionalTag((Element) v); + break closing; + } + } + else + break closing; + } + while (v == Boolean.FALSE && !stack.isEmpty()); + } + } + } + + stack.add(new hTag(tElement)); + } + + /** + * Clear the stack. + */ + public void restart() + { + stack.clear(); + } + + /** + * Check if this tag is valid for the current context. Return Boolean.True if + * it is OK, Boolean.False if it is surely not OK or the Element that the + * content model recommends to insert making the situation ok. If Boolean.True + * is returned, the content model current position is moved forward. Otherwise + * this position remains the same. + * + * @param tElement + * @return + */ + public Object tagIsValidForContext(TagElement tElement) + { + // Check the current content model, if one is available. + node cv = getCurrentContentModel(); + + if (cv != null) + return cv.show(tElement.getElement()); + + // Check exclusions and inclusions. + ListIterator iter = stack.listIterator(stack.size()); + hTag t = null; + final int idx = tElement.getElement().index; + + // Check only known tags. + if (idx >= 0) + { + BitSet inclusions = new BitSet(); + while (iter.hasPrevious()) + { + t = (hTag) iter.previous(); + if (! t.forcibly_closed) + { + if (t.element.exclusions != null + && t.element.exclusions.get(idx)) + return Boolean.FALSE; + + if (t.element.inclusions != null) + inclusions.or(t.element.inclusions); + } + } + if (! inclusions.get(idx)) + { + // If we need to insert something, and cannot do this, but + // it is allowed to insert the paragraph here, insert the + // paragraph. + Element P = dtd.getElement(HTML_401F.P); + if (inclusions.get(P.index)) + return P; + else + return Boolean.FALSE; + } + } + return Boolean.TRUE; + } + + /** + * Validate tag without storing in into the tag stack. This is called + * for the empty tags and results the subsequent calls to the openTag + * and closeTag. + */ + public void validateTag(TagElement tElement, htmlAttributeSet parameters) + { + openTag(tElement, parameters); + closeTag(tElement); + } + + /** + * Check for mandatory elements, subsequent to the last tag: + * @param tElement The element that will be inserted next. + */ + protected void checkContentModel(TagElement tElement, boolean first) + { + if (stack.isEmpty()) + return; + + hTag last = (hTag) stack.getLast(); + if (last.validationTrace == null) + return; + + Object r = last.validationTrace.show(tElement.getElement()); + if (r == Boolean.FALSE) + s_error("The <" + last.element + "> does not match the content model " + + last.validationTrace + ); + else if (r instanceof Element) // The content model recommends insertion of this element + { + if (!first) + closeTag(last.tgElement); + handleSupposedStartTag((Element) r); + openTag(new TagElement((Element) r), null); + } + } + + /** + * The method is called when the tag must be closed because + * it does not allow the subsequent elements inside its context + * or the end of stream has been reached. The parser is only + * informed if the element being closed does not require the + * end tag (the "omitEnd" flag is set). + * The closing message must be passed to the parser mechanism + * before passing message about the opening the next tag. + * + * @param element The tag being fictionally (forcibly) closed. + */ + protected abstract void handleSupposedEndTag(Element element); + + /** + * The method is called when the validator decides to open the + * tag on its own initiative. This may happen if the content model + * includes the element with the optional (supposed) start tag. + * + * @param element The tag being opened. + */ + protected abstract void handleSupposedStartTag(Element element); + + /** + * Handles the error message. This method must be overridden to pass + * the message where required. + * @param msg The message text. + */ + protected abstract void s_error(String msg); + + /** + * Validate the parameters, report the error if the given parameter is + * not in the parameter set, valid for the given attribute. The information + * about the valid parameter set is taken from the Element, enclosed + * inside the tag. The method does not validate the default parameters. + * @param tag The tag + * @param parameters The parameters of this tag. + */ + protected void validateParameters(TagElement tag, htmlAttributeSet parameters) + { + if (parameters == null || + parameters == htmlAttributeSet.EMPTY_HTML_ATTRIBUTE_SET || + parameters == SimpleAttributeSet.EMPTY + ) + return; + + Enumeration enumeration = parameters.getAttributeNames(); + + while (enumeration.hasMoreElements()) + { + validateAttribute(tag, parameters, enumeration); + } + + // Check for missing required values. + AttributeList a = tag.getElement().getAttributes(); + + while (a != null) + { + if (a.getModifier() == DTDConstants.REQUIRED) + if (parameters.getAttribute(a.getName()) == null) + { + s_error("Missing required attribute '" + a.getName() + "' for <" + + tag.getHTMLTag() + ">" + ); + } + a = a.next; + } + } + + private node getCurrentContentModel() + { + if (!stack.isEmpty()) + { + hTag last = (hTag) stack.getLast(); + return last.validationTrace; + } + else + return null; + } + + private void closeLast() + { + handleSupposedEndTag(((hTag) stack.getLast()).element); + stack.removeLast(); + } + + private void openFictionalTag(Element e) + { + handleSupposedStartTag(e); + stack.add(new hTag(new TagElement(e, true))); + if (!e.omitStart()) + s_error("<" + e + "> is expected (supposing it)"); + } + + private void validateAttribute(TagElement tag, htmlAttributeSet parameters, + Enumeration enumeration + ) + { + Object foundAttribute; + AttributeList dtdAttribute; + foundAttribute = enumeration.nextElement(); + dtdAttribute = tag.getElement().getAttribute(foundAttribute.toString()); + if (dtdAttribute == null) + { + CPStringBuilder valid = + new CPStringBuilder("The tag <" + tag.getHTMLTag() + + "> cannot contain the attribute '" + foundAttribute + + "'. The valid attributes for this tag are: " + ); + + AttributeList a = tag.getElement().getAttributes(); + + while (a != null) + { + valid.append(a.name.toUpperCase()); + valid.append(' '); + a = a.next; + } + s_error(valid.toString()); + } + + else + { + String value = parameters.getAttribute(foundAttribute).toString(); + + if (dtdAttribute.type == DTDConstants.NUMBER) + validateNumberAttribute(tag, foundAttribute, value); + + if (dtdAttribute.type == DTDConstants.NAME || + dtdAttribute.type == DTDConstants.ID + ) + validateNameOrIdAttribute(tag, foundAttribute, value); + + if (dtdAttribute.values != null) + validateAttributeWithValueList(tag, foundAttribute, dtdAttribute, + value + ); + } + } + + private void validateAttributeWithValueList(TagElement tag, + Object foundAttribute, + AttributeList dtdAttribute, + String value + ) + { + if (!dtdAttribute.values.contains(value.toLowerCase()) && + !dtdAttribute.values.contains(value.toUpperCase()) + ) + { + CPStringBuilder valid; + if (dtdAttribute.values.size() == 1) + valid = + new CPStringBuilder("The attribute '" + foundAttribute + + "' of the tag <" + tag.getHTMLTag() + + "> cannot have the value '" + value + + "'. The only valid value is " + ); + else + valid = + new CPStringBuilder("The attribute '" + foundAttribute + + "' of the tag <" + tag.getHTMLTag() + + "> cannot have the value '" + value + "'. The " + + dtdAttribute.values.size() + + " valid values are: " + ); + + Enumeration vv = dtdAttribute.values.elements(); + while (vv.hasMoreElements()) + { + valid.append('"'); + valid.append(vv.nextElement()); + valid.append("\" "); + } + s_error(valid.toString()); + } + } + + private void validateNameOrIdAttribute(TagElement tag, Object foundAttribute, + String value + ) + { + boolean ok = true; + + if (!Character.isLetter(value.charAt(0))) + ok = false; + + char c; + for (int i = 0; i < value.length(); i++) + { + c = value.charAt(i); + if (!( + Character.isLetter(c) || Character.isDigit(c) || + "".indexOf(c) >= 0 + ) + ) + ok = false; + } + if (!ok) + s_error("The '" + foundAttribute + "' attribute of the tag <" + + tag.getHTMLTag() + "> must start from letter and consist of " + + "letters, digits, hypens, colons, underscores and periods. " + + "It cannot be '" + value + "'" + ); + } + + private void validateNumberAttribute(TagElement tag, Object foundAttribute, + String value + ) + { + try + { + Integer.parseInt(value); + } + catch (NumberFormatException ex) + { + s_error("The '" + foundAttribute + "' attribute of the tag <" + + tag.getHTMLTag() + "> must be a valid number and not '" + + value + "'" + ); + } + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/models/PCDATAonly_model.java b/libjava/classpath/gnu/javax/swing/text/html/parser/models/PCDATAonly_model.java new file mode 100644 index 000000000..5a19a1bc1 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/models/PCDATAonly_model.java @@ -0,0 +1,62 @@ +/* PCDATAonly_model.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.parser.models; + +import java.io.Serializable; + +/** + * The model, allowing only PCDATA in it (like for element OPTION). + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class PCDATAonly_model + extends node + implements Serializable +{ + private static final long serialVersionUID = 1; + + public PCDATAonly_model() + { + super((char) 0, (char) 0, null); + } + + public Object show(Object x) + { + return x.toString().equalsIgnoreCase("#pcdata") ? Boolean.TRUE : Boolean.FALSE; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/models/TableRowContentModel.java b/libjava/classpath/gnu/javax/swing/text/html/parser/models/TableRowContentModel.java new file mode 100644 index 000000000..14514d584 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/models/TableRowContentModel.java @@ -0,0 +1,77 @@ +/* TableRowContentModel.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.parser.models; + +import java.io.Serializable; + +import javax.swing.text.html.parser.DTD; +import javax.swing.text.html.parser.Element; + +/** + * Table row content model. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class TableRowContentModel + extends node + implements Serializable +{ + private static final long serialVersionUID = 1; + final Element TD; + + public TableRowContentModel(DTD dtd) + { + super((char) 0, (char) 0, null); + TD = dtd.getElement("TD"); + } + + public Object show(Object x) + { + // Always accept TD and TH + String s = x.toString(); + if (s.equalsIgnoreCase("TD") || s.equalsIgnoreCase("TH")) + return Boolean.TRUE; + + // Suggest closing in response to TR: + if (s.equalsIgnoreCase("TR")) + return Boolean.FALSE; + + // Recommend TD for other cases: + return TD; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/models/list.java b/libjava/classpath/gnu/javax/swing/text/html/parser/models/list.java new file mode 100644 index 000000000..1ff22f8cd --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/models/list.java @@ -0,0 +1,384 @@ +/* list.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.parser.models; + +import gnu.java.lang.CPStringBuilder; + +import java.io.Serializable; + +/** + * Part of the internal representation of the content model. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class list + extends node + implements Serializable +{ + private static final long serialVersionUID = 1; + + /** + * Setting to true means that the list nodes must always be connected + * by the same operation. This is far safer and clearer, but not + * required by default standard. + */ + public static boolean CLEAR; + + /** + * A list of nodes. + */ + public final node[] nodes; + + /** + * Creates a new model list that is a member of some enclosing list. + * @param binary_operator An operator with that this list is connected + * with other members of the enclosing list. + * @param unary_operator The unary operator for this list. + * @param a_nodes The nodes inside this list. + */ + public list(char binary_operator, char unary_operator, node[] a_nodes) + { + super(binary_operator, unary_operator, a_nodes); + nodes = a_nodes; + } + + /** + * Creates a new model list. Assigns the previous field. + * @param a_nodes The nodes for this list. + * @throws an error if the node elements are connected by the + * different operations. This is not supported, use grouping. + */ + public list(node[] a_nodes) + throws Error + { + this(',', (char) 0, a_nodes); + + int operation = nodes [ 0 ].binary; + + for (int i = 0; i < nodes.length; i++) + { + if (CLEAR && nodes [ i ].binary != operation) + throw new Error("List members can only be connected by " + + "the same operation, use grouping" + ); + + if (i > 0) + nodes [ i ].previous = nodes [ i - 1 ]; + } + } + + /** + * Returns true if all members in the list are closed. + */ + public boolean isClosed() + { + if (super.isClosed()) + return true; + for (int i = 0; i < nodes.length; i++) + { + if (!nodes [ i ].isClosed()) + return false; + } + return true; + } + + /** + * Find the token that could match as the next token in + * the token list. + * + * @return Such token object or null if none is found. + */ + public Object findFreeNode() + { + Object fn; + for (int j = 0; j < nodes.length; j++) + { + if (!nodes [ j ].isClosed()) + { + fn = nodes [ j ].findFreeNode(); + if (fn != null) + return fn; + } + } + return null; + } + + /** + * Tries to match this list agains the given token sequence. + * @param tokens the sequence of the tokens to match. + * @return true if the valid match is found. + */ + public boolean matches(Object[] tokens) + { + reset(); + + Object x; + boolean m; + boolean matched = false; + + for (int i = 0; i < tokens.length; i++) + { + matched = false; + x = tokens [ i ]; + + nodescan: + for (int j = 0; j < nodes.length; j++) + { + if (!nodes [ j ].isClosed()) + { + m = nodes [ j ].performMatch(x); + + if (m) + { + matched = true; + break nodescan; + } + } + } + if (!matched) + return false; + } + + boolean valid = true; + + for (int i = 0; i < nodes.length; i++) + { + if (!nodes [ i ].valid()) + valid = false; + } + + return valid; + } + + /** + * The list never closes, despite it is trated as closed + * if all members in the list are closed. + * @return false. + */ + public boolean mustClose() + { + return false; + } + + /** + * Perform a match operation for the single token + * against this list. + * @param token a token to match. + * @return true if the match is found. + */ + public boolean performMatch(Object token) + { + boolean ok = false; + Matching: + for (int i = 0; i < nodes.length; i++) + { + ok = nodes [ i ].performMatch(token); + + if (ok) + break Matching; + } + + if (ok) + matches(); + + return ok; + } + + /** + * Prepeares the list for the next matching operation. + */ + public void reset() + { + super.reset(); + for (int i = 0; i < nodes.length; i++) + nodes [ i ].reset(); + } + + /** + * Check if the provided token can match as a next token in the + * list. In the case of match, the list state changes, moving + * current position after the matched token. However if this method + * returns a suggested new token to insert before the provided one, + * the state of the list does not change. + * @return Boolean.TRUE if the match is found, + * Boolean.FALSE if the match is not possible and no token can be + * inserted to make the match valid. Otherwise, returns the + * token object that can be inserted before the last token in the + * list, probably (not for sure) making the match valid. + * If the object is an instance of Element or TagElement, + * it is first ensured that the object flag "omit start" is set. + */ + public Object show(Object x) + { + boolean m; + boolean matched = false; + + nodescan: + for (int j = 0; j < nodes.length; j++) + { + if (!nodes [ j ].isClosed()) + { + m = nodes [ j ].performMatch(x); + + if (m) + { + matched = true; + break nodescan; + } + else + { + // For comma operation, only first not closed + // node must be tested for a match. + // unless it allows matching zero times. + if (binary == ',' && + !(nodes [ j ].unary == '?' || nodes [ j ].unary == '*') + ) + break nodescan; + } + } + } + + if (!matched) + { + // Find and return that would be matched. + Object freeNode = findFreeNode(); + if (freeNode == null) + return Boolean.FALSE; + else + return freeNode; + } + + for (int i = 0; i < nodes.length; i++) + if (!nodes [ i ].validPreliminary()) + { + return Boolean.FALSE; + } + + return Boolean.TRUE; + } + + /** + * Returns a string representation of the list. + * @return String representation, similar to BNF expression. + */ + public String toString() + { + CPStringBuilder b = new CPStringBuilder(); + b.append(" ( "); + for (int i = 0; i < nodes.length; i++) + { + if (i > 0) + b.append(" " + (char) nodes [ i ].binary + " "); + b.append(nodes [ i ]); + } + + b.append(" )"); + if (unary != 0) + b.append((char) unary); + else + b.append(' '); + return b.toString(); + } + + /** + * Returns true if all memebers in the list are valid. + */ + public boolean valid() + { + for (int i = 0; i < nodes.length; i++) + { + if (!nodes [ i ].valid()) + return false; + } + return true; + } + + /** + * Returns true if all memebers in the list are either valid + * or unvisited. The unvisited members can become valid after + * more tokens will be shown. + */ + public boolean validPreliminary() + { + if (silenceAllowed()) + { + boolean everVisited = false; + for (int i = 0; i < nodes.length; i++) + { + if (nodes [ i ].visits > 0) + { + everVisited = true; + break; + } + } + if (!everVisited) + return true; + } + + for (int i = 0; i < nodes.length; i++) + { + if (!nodes [ i ].validPreliminary()) + return false; + } + return true; + } + + /** + * Closes all members in the list. + */ + protected void close() + { + super.close(); + for (int i = 0; i < nodes.length; i++) + { + nodes [ i ].close(); + } + } + + /** + * Compare given token with the token of this node. + * If the token represents a list, the call may be + * delegeted to the child subnodes. + * @param a_token A token to compare. + * @return True if the token matches the token of this node. + */ + protected boolean compare(Object a_token) + { + return performMatch(a_token); + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/models/noTagModel.java b/libjava/classpath/gnu/javax/swing/text/html/parser/models/noTagModel.java new file mode 100644 index 000000000..8aac14d8e --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/models/noTagModel.java @@ -0,0 +1,75 @@ +/* noTagModel.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.parser.models; + +import java.io.Serializable; + +/** + * Disallows a single given tag at the current content level only. + *

    @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)

    + */ +public class noTagModel + extends node + implements Serializable +{ + private static final long serialVersionUID = 1; + final String[] no; + + public noTagModel(String[] noTag) + { + super((char) 0, (char) 0, null); + no = noTag; + } + + public noTagModel(String noTag) + { + super((char) 0, (char) 0, null); + no = new String[] { noTag }; + } + + public Object show(Object x) + { + for (int i = 0; i < no.length; i++) + { + if (x.toString().equalsIgnoreCase(no [ i ])) + return Boolean.FALSE; + } + return Boolean.TRUE; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/models/node.java b/libjava/classpath/gnu/javax/swing/text/html/parser/models/node.java new file mode 100644 index 000000000..f45a13b3e --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/models/node.java @@ -0,0 +1,339 @@ +/* node.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.parser.models; + +import gnu.java.lang.CPStringBuilder; + +import java.io.Serializable; + +/** + * Part of the internal representation of the content model. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class node + implements Serializable +{ + private static final long serialVersionUID = 1; + + /** + * The token to match (can be instance of list). + */ + public Object token; + + /** + * True for the node that cannot be visited again. + */ + public boolean _closed; + + /** + * The binary operation for this node. + */ + public char binary; + + /** + * The unary opeation for this node. + */ + public char unary; + + /** + * The number of times the node already was visited. + */ + public int visits; + + /** + * The previous node in content model (used for closing nodes). + */ + public node previous; + + /** + * Creates a new node. + * @param binary_operator The operator, connecting all nodes in the list. + * The nodes, connected by the different operators, must be arranged into + * the different lists. + * @param unary_operator The unary operator for this node or zero if + * no such was specified. + * @param token The token to match. This can be either a string or + * the new instance of the list. + * @param a_previous The previous node in the list, null for the first + * node. This is used for propagating the closing operation for the + * comma delimited list. + */ + public node(char binary_operator, char unary_operator, Object a_token) + { + if (a_token != null) + if (a_token.getClass().equals(node.class)) + throw new Error("Creating node in node is redundant and ineffective."); + + binary = binary_operator; + unary = unary_operator; + token = a_token; + } + + /** + * Checks if this node is in the closed state. + * @return True if the node is closed. + */ + public boolean isClosed() + { + return _closed; + } + + /** + * Check if closing this node means closing the previous node. + */ + public boolean closePrevious() + { + return binary == ','; + } + + /** + * Return the token object if it could match as a next token in + * a token list of null if it could not. + * @return + */ + public Object findFreeNode() + { + boolean ok; + if (isClosed() || silenceAllowed()) + return null; + + // Try if the node would stay valid after a one more visit. + visits++; + ok = valid(); + visits--; + + if (ok) + { + if (token instanceof node) + return ((node) token).findFreeNode(); + else + return token; + } + else + return null; + } + + /** + * Check if the current situation is such that the node must be closed + * now. + */ + public boolean mustClose() + { + switch (unary) + { + case 0 : + return true; + + case '*' : + return false; + + case '+' : + return false; + + case '?' : + return visits <= 1; + + default : + throw new Error("Invalid unary operation " + unary + " ( '" + + (char) unary + "' )" + ); + } + } + + /** + * Do the match operation with the given token. This sets various + * flags. + * @param a_token The token to match. + * @return true if the the token matches node, false if it does not match + * or if the node is closed. + */ + public boolean performMatch(Object a_token) + { + if (isClosed()) + return false; + + boolean matches = compare(a_token); + if (matches) + matches(); + + return matches; + } + + /** + * Prepares the node for matching against a new list of tokens. + */ + public void reset() + { + _closed = false; + visits = 0; + } + + /** + * Check if the provided token can match this node. + * In the case of match, the node state changes, moving + * current position after the matched token. However if this method + * returns a suggested new token to insert before the provided one, + * the state of the list does not change. + * @return Boolean.TRUE if the match is found, + * Boolean.FALSE if the match is not possible and no token can be + * inserted to make the match valid. Otherwise, returns the + * token object that can be inserted before the last token in the + * list, probably (not for sure) making the match valid. + */ + public Object show(Object x) + { + if (compare(x)) + return performMatch(x) ? Boolean.TRUE : Boolean.FALSE; + + Object recommended = findFreeNode(); + return recommended != null ? recommended : Boolean.FALSE; + } + + /** + * Check if it would be a valid case if this node is visited zero times. + * Nodes with unary operator * or ? need not be matched to make a + * model valid. + */ + public boolean silenceAllowed() + { + return unary == '?' || unary == '*'; + } + + /** + * Returns a string representation of the list. + * @return String representation, similar to BNF expression. + */ + public String toString() + { + CPStringBuilder b = new CPStringBuilder(); + + b.append(token); + if (unary != 0) + b.append((char) unary); + else + b.append('\''); + + return b.toString(); + } + + /** + * Check if the node state is valid. + */ + public boolean valid() + { + switch (unary) + { + case 0 : + if (binary == '|') + return true; + else + return visits == 1; + + case '*' : + return true; + + case '+' : + return visits > 0; + + case '?' : + return visits <= 1; + + default : + throw new Error("Invalid unary operation " + unary + " ( '" + + (char) unary + "' )" + ); + } + } + + public boolean validPreliminary() + { + return visits == 0 || valid(); + } + + /** + * Closes this node and, if closePrevious() returs true, calls close() for + * the previous node. + */ + protected void close() + { + _closed = true; + if (previous != null && closePrevious()) + previous.close(); + } + + /** + * Compare the provided token object with the token object of this node. + */ + protected boolean compare(Object a_token) + { + if (token instanceof Object[]) + throw new Error("Invalid token object, probably the 'list' " + + "should be used. " + ); + + if (token instanceof node[]) + throw new Error("Do not use 'node' for the array of nodes, use 'list'. "); + + if (token instanceof node) + { + return ((node) token).performMatch(a_token); + } + + boolean rt = false; + + if (token == a_token) + rt = true; + if (token.equals(a_token)) + rt = true; + if (token.toString().equalsIgnoreCase(a_token.toString())) + rt = true; + + return rt; + } + + /** + * Fire the changes that must happen then the token matches this node. + */ + protected void matches() + { + visits++; + if (mustClose()) + close(); + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/models/package.html b/libjava/classpath/gnu/javax/swing/text/html/parser/models/package.html new file mode 100644 index 000000000..18e61aede --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/models/package.html @@ -0,0 +1,53 @@ + + + + +GNU Classpath - gnu.javax.swing.text.html.parser.models + + +

    This package contains classes for working with content models. In this implementation, the +standardized content model is pre-processed by transformer into an instance of +node. Node holds a single element of the content model with the optional unary operation. +The derived class list holds multiple nodes connected by the same binary operation. +As the members of this list can also be lists itself, these structures support +the most of required operations. Several cases when the model cannot be expressed using +BNF syntax are handled providing specialised classes that are also derived from node. +

    +@author Audrius Meskauskas, Lithuania + + diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/models/transformer.java b/libjava/classpath/gnu/javax/swing/text/html/parser/models/transformer.java new file mode 100644 index 000000000..22ae3c3fa --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/models/transformer.java @@ -0,0 +1,201 @@ +/* transformer.java -- Content model transforms. + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.parser.models; + +import java.io.Serializable; + +import javax.swing.text.html.parser.ContentModel; +import javax.swing.text.html.parser.DTD; + +/** + * Transforms the standard ContentModel tree into the internal representation, + * used in this implementation. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class transformer + implements Serializable +{ + private static final long serialVersionUID = 1; + + /** + * All binary operators. + */ + protected static String binary = "&|,"; + + /** + * All unary operators. + */ + protected static String unary = "+*?"; + + /** + * Measure length of the linked list of the content models. + * @param c The heading element of the linked list. + * @return the length of the list (0 for null 1 if c!=null and c.next==null, + * etc. + */ + public static int measureChainLength(ContentModel c) + { + if (c == null) + return 0; + else + return measureChainLength(c.next) + 1; + } + + /** + * Transform into internal representation without usind dtd. + * This should be used only for testing. + */ + public static node transform(ContentModel c) + { + return transform(c, null); + } + + /** + * Transform into internal representation. + * @param c a model to transform + * @return a transformed model + * @throws Error if the model structure contains errors. + */ + public static node transform(ContentModel c, DTD dtd) + { + // Handle the special cases first. + if (c.content instanceof node) + return (node) c.content; + + // Do the typical transform. + node n; + + /* Case with the single token */ + if (c.next == null) + { + n = optionalTransform(c, dtd); + } + else /* Case with the chain of the multiple tokens. */ + { + node[] l = new node[ measureChainLength(c) ]; + ContentModel m = c; + for (int i = 0; i < l.length; i++) + { + if (m.content instanceof ContentModel) + { + ContentModel nested = (ContentModel) m.content; + if (nested.next == null && + !(nested.content instanceof ContentModel) + ) + { + l [ i ] = + new node((char) m.type, (char) nested.type, nested.content); + } + else + { + l [ i ] = transform(nested, dtd); + } + } + else + l [ i ] = new node((char) 0, (char) 0, m.content); + addtype(l [ i ], (char) m.type); + m = m.next; + } + + if (isBinary(c.type)) + for (int i = 0; i < l.length; i++) + { + l [ i ].binary = (char) c.type; + } + + n = new list(l); + } + + addtype(n, (char) c.type); + + return n; + } + + /** + * True for binary operator + * @param c a character to test + * @return true for [ ,&| ], false otherwise. + */ + private static boolean isBinary(int c) + { + return binary.indexOf((char) c) >= 0; + } + + /** + * True for unary operator. + * @param c a character to test + * @return true for [ +?* ], false otherwise. + */ + private static boolean isUnary(int c) + { + return unary.indexOf((char) c) >= 0; + } + + /** + * Assign an operation type for the given node. + * @param n A node to set the operation to. + * @param type Either binary or unary operation, is assigned to the + * corresponding field of the node. + * @throws error if the operation type is not + * representing a valid unary or binary operation. + */ + private static void addtype(node n, char type) + { + if (isBinary(type)) + n.binary = type; + + else if (isUnary(type)) + n.unary = type; + + else if (type != 0) + throw new Error("Invalid operation '" + (char) type + "'"); + } + + private static node optionalTransform(ContentModel c, DTD dtd) + { + node n; + if (c.content instanceof ContentModel) + n = transform((ContentModel) c.content, dtd); + else + + /* A single token with the specified operation */ + n = new node((char) 0, (char) 0, c.content); + return n; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/package.html b/libjava/classpath/gnu/javax/swing/text/html/parser/package.html new file mode 100644 index 000000000..cd050f9c2 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/package.html @@ -0,0 +1,51 @@ + + + + +GNU Classpath - javax.swing.text.html.parser + + +

    Provides the error tolerant, DTD-driven HTML 4.01 parser. +The parser that is used in web robots, html content analysers, +web browsers, web editors and other related applications. +It should compativle with the older HTML versions, supporting +obsoleted HTML featues. This package also includes some +supporting classes.

    +@author Audrius Meskauskas, Lithuania + + diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/Parser.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/Parser.java new file mode 100644 index 000000000..cdefb75c8 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/Parser.java @@ -0,0 +1,1532 @@ +/* Parser.java -- HTML parser. + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.parser.support; + +import gnu.java.lang.CPStringBuilder; + +import gnu.javax.swing.text.html.parser.htmlAttributeSet; +import gnu.javax.swing.text.html.parser.htmlValidator; +import gnu.javax.swing.text.html.parser.support.low.Constants; +import gnu.javax.swing.text.html.parser.support.low.ParseException; +import gnu.javax.swing.text.html.parser.support.low.ReaderTokenizer; +import gnu.javax.swing.text.html.parser.support.low.Token; +import gnu.javax.swing.text.html.parser.support.low.node; +import gnu.javax.swing.text.html.parser.support.low.pattern; + +import java.io.IOException; +import java.io.Reader; + +import java.util.Comparator; +import java.util.Set; +import java.util.TreeSet; +import java.util.Vector; + +import javax.swing.text.ChangedCharSetException; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.html.HTML; +import javax.swing.text.html.parser.AttributeList; +import javax.swing.text.html.parser.DTD; +import javax.swing.text.html.parser.DTDConstants; +import javax.swing.text.html.parser.Element; +import javax.swing.text.html.parser.Entity; +import javax.swing.text.html.parser.TagElement; + +/** + *

    A simple error-tolerant HTML parser that uses a DTD document + * to access data on the possible tokens, arguments and syntax.

    + *

    The parser reads an HTML content from a Reader and calls various + * notifying methods (which should be overridden in a subclass) + * when tags or data are encountered.

    + *

    Some HTML elements need no opening or closing tags. The + * task of this parser is to invoke the tag handling methods also when + * the tags are not explicitly specified and must be supposed using + * information, stored in the DTD. + * For example, parsing the document + *

    <table><tr><td>a<td>b<td>c</tr>
    + * will invoke exactly the handling methods exactly in the same order + * (and with the same parameters) as if parsing the document:
    + * <html><head></head><body><table>< + * tbody><tr><td>a</td><td>b + * </td><td>c</td></tr>< + * /tbody></table></body></html>

    + * (supposed tags are given in italics). The parser also supports + * obsolete elements of HTML syntax.

    + *

    + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class Parser + extends ReaderTokenizer + implements DTDConstants +{ + /** + * The current html tag. + */ + public Token hTag = new Token(); + + /** + * The document template description that will be used to parse the documents. + */ + protected DTD dtd; + + /** + * The value of this field determines whether or not the Parser will be + * strict in enforcing SGML compatibility. The default value is false, + * stating that the parser should do everything to parse and get at least + * some information even from the incorrectly written HTML input. + */ + protected boolean strict; + + /** + * This fields has positive values in preformatted tags. + */ + protected int preformatted = 0; + + /** + * The set of the document tags. This field is used for supporting + * markFirstTime(). + */ + private Set documentTags = + new TreeSet(new Comparator() + { + public int compare(Object a, Object b) + { + return ((String) a).compareToIgnoreCase((String) b); + } + } + ); + + /** + * The buffer to collect the incremental output like text or coment. + */ + private final StringBuffer buffer = new StringBuffer(); + + /** + * The buffer to store the document title. + */ + private final StringBuffer title = new StringBuffer(); + + /** + * The current token. + */ + private Token t; + + /** + * True means that the 'title' tag of this document has + * already been handled. + */ + private boolean titleHandled; + + /** + * True means that the 'title' tag is currently open and all + * text is also added to the title buffer. + */ + private boolean titleOpen; + + /** + * The attributes of the current HTML element. + * Package-private to avoid an accessor method. + */ + htmlAttributeSet attributes = + htmlAttributeSet.EMPTY_HTML_ATTRIBUTE_SET; + + /** + * The validator, controlling the forcible closing of the tags that + * (in accordance to dtd) are not allowed in the current context. + */ + private htmlValidator validator; + + /** + * Provides the default values for parameters in the case when these + * values are defined in the DTD. + */ + private parameterDefaulter defaulter; + + /** + * The text pre-processor for handling line ends and tabs. + */ + private textPreProcessor textProcessor = new textPreProcessor(); + + /** + * Creates a new Parser that uses the given + * {@link javax.swing.text.html.parser.DTD }. The only standard way + * to get an instance of DTD is to construct it manually, filling in + * all required fields. + * @param a_dtd The DTD to use. The parser behaviour after passing null + * as an argument is not documented and may vary between implementations. + */ + public Parser(DTD a_dtd) + { + if (a_dtd == null) + dtd = gnu.javax.swing.text.html.parser.HTML_401F.getInstance(); + else + dtd = a_dtd; + + defaulter = new parameterDefaulter(dtd); + + validator = + new htmlValidator(dtd) + { + /** + * Handles the error message. This method must be overridden to pass + * the message where required. + * @param msg The message text. + */ + protected void s_error(String msg) + { + error(msg); + } + + /** + * The method is called when the tag validator decides to close the + * tag on its own initiative. After reaching the end of stream, + * The tag validator closes all unclosed elements that are required + * to have the end (closing) tag. + * + * @param tElement The tag being fictionally (forcibly) closed. + */ + protected void handleSupposedEndTag(Element tElement) + { + // The tag is cloned as the original tElement is the + // element from the starting tag - may be accidently used + // somewhere else. + TagElement tag = makeTag(tElement, true); + _handleEndTag_remaining(tag); + } + + /** + * The method is called when the the tag validator decides to open + * the new tag on its own initiative. The tags, opened in this + * way, are HTML, HEAD and BODY. The attribute set is temporary + * assigned to the empty one, the previous value is + * restored before return. + * + * @param tElement The tag being fictionally (forcibly) closed. + */ + protected void handleSupposedStartTag(Element tElement) + { + TagElement tag = makeTag(tElement, true); + htmlAttributeSet were = attributes; + attributes = htmlAttributeSet.EMPTY_HTML_ATTRIBUTE_SET; + _handleStartTag(tag); + attributes = were; + } + }; + } + + /** + * Get the attributes of the current tag. + * @return The attribute set, representing the attributes of the current tag. + */ + public SimpleAttributeSet getAttributes() + { + return new SimpleAttributeSet(attributes); + } + + /** + * Invokes the error handler. The default method in this implementation + * delegates the call to handleError, also providing the current line. + */ + public void error(String msg) + { + error(msg, getTokenAhead()); + } + + public void error(String msg, Token atToken) + { + if (atToken != null) + handleError(atToken.where.beginLine, + msg + ": line " + atToken.where.beginLine + + ", absolute pos " + atToken.where.startPosition + ); + else + handleError(0, msg); + } + + /** + * Invokes the error handler. The default method in this implementation + * delegates the call to error (parm1+": '"+parm2+"'"). + */ + public void error(String msg, String invalid) + { + error(msg + ": '" + invalid + "'"); + } + + /** + * Invokes the error handler. The default method in this implementation + * delegates the call to error (parm1+" "+ parm2+" "+ parm3). + */ + public void error(String parm1, String parm2, String parm3) + { + error(parm1 + " " + parm2 + " " + parm3); + } + + /** + * Invokes the error handler. The default method in this implementation + * delegates the call to error (parm1+" "+ parm2+" "+ parm3+" "+ parm4). + */ + public void error(String parm1, String parm2, String parm3, String parm4) + { + error(parm1 + " " + parm2 + " " + parm3 + " " + parm4); + } + + public void flushAttributes() + { + } + + /** + * Parse the HTML text, calling various methods in response to the + * occurence of the corresponding HTML constructions. + * @param reader The reader to read the source HTML from. + * @throws IOException If the reader throws one. + */ + public synchronized void parse(Reader reader) + throws IOException + { + reset(reader); + restart(); + try + { + parseDocument(); + validator.closeAll(); + } + catch (ParseException ex) + { + if (ex != null) + { + error("Unable to continue parsing the document", ex.getMessage()); + + Throwable cause = ex.getCause(); + if (cause instanceof IOException) + throw (IOException) cause; + } + } + } + + /** + * Parses DTD markup declaration. Currently returns null without action. + * @return null. + * @throws IOException + */ + public String parseDTDMarkup() + throws IOException + { + return null; + } + + /** + * Parse SGML insertion ( <! ... > ). When the + * the SGML insertion is found, this method is called, passing + * SGML in the string buffer as a parameter. The default method + * returns false without action and can be overridden to + * implement user - defined SGML support. + *

    + * If you need more information about SGML insertions in HTML documents, + * the author suggests to read SGML tutorial on + * {@link http://www.w3.org/TR/WD-html40-970708/intro/sgmltut.html}. + * We also recommend Goldfarb C.F (1991) The SGML Handbook, + * Oxford University Press, 688 p, ISBN: 0198537379. + *

    + * @param strBuff + * @return true if this is a valid DTD markup declaration. + * @throws IOException + */ + public boolean parseMarkupDeclarations(StringBuffer strBuff) + throws IOException + { + return false; + } + + /** + * Get the first line of the last parsed token. + */ + protected int getCurrentLine() + { + return hTag.where.beginLine; + } + + /** + * Read parseable character data, add to buffer. + * @param clearBuffer If true, buffer if filled by CDATA section, + * otherwise the section is appended to the existing content of the + * buffer. + * + * @throws ParseException + */ + protected void CDATA(boolean clearBuffer) + throws ParseException + { + Token start = hTag = getTokenAhead(); + + if (clearBuffer) + buffer.setLength(0); + + // Handle expected EOF. + if (start.kind == EOF) + return; + + read: + while (true) + { + t = getTokenAhead(); + if (t.kind == EOF) + { + error("unexpected eof", t); + break read; + } + else if (t.kind == BEGIN) + break read; + else if (t.kind == Constants.ENTITY) + { + resolveAndAppendEntity(t); + getNextToken(); + } + else + { + append(t); + getNextToken(); + } + } + hTag = new Token(start, getTokenAhead(0)); + if (buffer.length() != 0) + _handleText(); + } + + /** + * Process Comment. This method skips till --> without + * taking SGML constructs into consideration. The supported SGML + * constructs are handled separately. + */ + protected void Comment() + throws ParseException + { + buffer.setLength(0); + + Token start = hTag = mustBe(BEGIN); + optional(WS); + mustBe(EXCLAMATION); + optional(WS); + mustBe(DOUBLE_DASH); + + Token t; + Token last; + + comment: + while (true) + { + t = getTokenAhead(); + if (t.kind == EOF) + { + handleEOFInComment(); + last = t; + break comment; + } + else if (COMMENT_END.matches(this)) + { + mustBe(DOUBLE_DASH); + optional(WS); + last = mustBe(END); + break comment; + } + else if (COMMENT_TRIPLEDASH_END.matches(this)) + { + mustBe(DOUBLE_DASH); + t = mustBe(NUMTOKEN); + if (t.getImage().equals("-")) + { + append(t); + last = mustBe(END); + break comment; + } + else + { + buffer.append("--"); + append(t); + t = getTokenAhead(); + } + } + else + /* The lllll-- can match as NUMTOKEN */ + if ((t.getImage().endsWith("--")) && + ( + getTokenAhead(1).kind == END || + (getTokenAhead(1).kind == WS && getTokenAhead(2).kind == END) + ) + ) + { + buffer.append(t.getImage().substring(0, t.getImage().length() - 2)); + + /* Skip the closing > that we have already checked. */ + last = mustBe(t.kind); + break comment; + } + else + append(t); + mustBe(t.kind); + } + hTag = new Token(start, last); + + // Consume any whitespace immediately following a comment. + optional(WS); + handleComment(); + } + + /** + * Read a script. The text, returned without any changes, + * is terminated only by the closing tag SCRIPT. + */ + protected void Script() + throws ParseException + { + Token name; + + Token start = hTag = mustBe(BEGIN); + optional(WS); + + name = mustBe(SCRIPT); + + optional(WS); + + restOfTag(false, name, start); + + buffer.setLength(0); + + while (!SCRIPT_CLOSE.matches(this)) + { + append(getNextToken()); + } + + consume(SCRIPT_CLOSE); + + _handleText(); + + endTag(false); + _handleEndTag(makeTagElement(name.getImage(), false)); + } + + /** + * Process SGML insertion that is not a comment. + */ + protected void Sgml() + throws ParseException + { + if (COMMENT_OPEN.matches(this)) + Comment(); + else // skip till ">" + { + Token start = hTag = mustBe(BEGIN); + optional(WS); + mustBe(EXCLAMATION); + + buffer.setLength(0); + read: + while (true) + { + t = getNextToken(); + if (t.kind == Constants.ENTITY) + { + resolveAndAppendEntity(t); + } + else if (t.kind == EOF) + { + error("unexpected eof", t); + break read; + } + else if (t.kind == END) + break read; + else + append(t); + } + + try + { + parseMarkupDeclarations(buffer); + } + catch (IOException ex) + { + error("Unable to parse SGML insertion: '" + buffer + "'", + new Token(start, t) + ); + } + } + // Consume any whitespace that follows the Sgml insertion. + optional(WS); + } + + /** + * Read a style definition. The text, returned without any changes, + * is terminated only by the closing tag STYLE. + */ + protected void Style() + throws ParseException + { + Token name; + + Token start = hTag = mustBe(BEGIN); + optional(WS); + + name = mustBe(STYLE); + + optional(WS); + + restOfTag(false, name, start); + + buffer.setLength(0); + + while (!STYLE_CLOSE.matches(this)) + { + append(getNextToken()); + } + + consume(STYLE_CLOSE); + + _handleText(); + + endTag(false); + _handleEndTag(makeTagElement(name.getImage(), false)); + } + + /** + * Read a html tag. + */ + protected void Tag() + throws ParseException + { + mark(true); + + boolean closing = false; + Token name; + Token start = hTag = mustBe(BEGIN); + + optional(WS); + name = getNextToken(); + optional(WS); + + if (name.kind == SLASH) + { + closing = true; + name = getNextToken(); + } + + restOfTag(closing, name, start); + } + + /** + * A hook, for operations, preceeding call to handleText. + * Handle text in a string buffer. + * In non - preformatted mode, all line breaks immediately following the + * start tag and immediately before an end tag is discarded, + * \r, \n and \t are replaced by spaces, multiple space are replaced + * by the single one and the result is moved into array, + * passing it to handleText(). + */ + protected void _handleText() + { + char[] text; + + if (preformatted > 0) + text = textProcessor.preprocessPreformatted(buffer); + else + text = textProcessor.preprocess(buffer); + + if (text != null && text.length > 0 + // According to the specs we need to discard whitespace immediately + // before a closing tag. + && (text.length > 1 || text[0] != ' ' || ! TAG_CLOSE.matches(this))) + { + TagElement pcdata = new TagElement(dtd.getElement("#pcdata")); + attributes = htmlAttributeSet.EMPTY_HTML_ATTRIBUTE_SET; + _handleEmptyTag(pcdata); + + handleText(text); + if (titleOpen) + title.append(text); + } + } + + /** + * Add the image of this token to the buffer. + * @param t A token to append. + */ + protected final void append(Token t) + { + if (t.kind != EOF) + t.appendTo(buffer); + } + + /** + * Consume pattern that must match. + * @param p A pattern to consume. + */ + protected final void consume(pattern p) + { + node n; + for (int i = 0; i < p.nodes.length; i++) + { + n = p.nodes [ i ]; + if (n.optional) + optional(n.kind); + else + mustBe(n.kind); + } + } + + /** + * The method is called when the HTML end (closing) tag is found or if + * the parser concludes that the one should be present in the + * current position. The method is called immediatly + * before calling the handleEndTag(). + * @param omitted True if the tag is no actually present in the document, + * but is supposed by the parser (like </html> at the end of the + * document). + */ + protected void endTag(boolean omitted) + { + } + + /** + * Handle HTML comment. The default method returns without action. + * @param comment + */ + protected void handleComment(char[] comment) + { + } + + /** + * This is additionally called in when the HTML content terminates + * without closing the HTML comment. This can only happen if the + * HTML document contains errors (for example, the closing --;gt is + * missing. + */ + protected void handleEOFInComment() + { + error("Unclosed comment"); + } + + /** + * Handle the tag with no content, like <br>. The method is + * called for the elements that, in accordance with the current DTD, + * has an empty content. + * @param tag The tag being handled. + * @throws javax.swing.text.ChangedCharSetException + */ + protected void handleEmptyTag(TagElement tag) + throws javax.swing.text.ChangedCharSetException + { + } + + /** + * The method is called when the HTML closing tag ((like </table>) + * is found or if the parser concludes that the one should be present + * in the current position. + * @param tag The tag + */ + protected void handleEndTag(TagElement tag) + { + } + + /* Handle error that has occured in the given line. */ + protected void handleError(int line, String message) + { + } + + /** + * The method is called when the HTML opening tag ((like <table>) + * is found or if the parser concludes that the one should be present + * in the current position. + * @param tag The tag + */ + protected void handleStartTag(TagElement tag) + { + } + + /** + * Handle the text section. + *

    For non-preformatted section, the parser replaces + * \t, \r and \n by spaces and then multiple spaces + * by a single space. Additionaly, all whitespace around + * tags is discarded. + *

    + *

    For pre-formatted text (inside TEXAREA and PRE), the parser preserves + * all tabs and spaces, but removes one bounding \r, \n or \r\n, + * if it is present. Additionally, it replaces each occurence of \r or \r\n + * by a single \n.

    + * + * @param text A section text. + */ + protected void handleText(char[] text) + { + } + + /** + * Handle HTML <title> tag. This method is invoked when + * both title starting and closing tags are already behind. + * The passed argument contains the concatenation of all + * title text sections. + * @param title The title text. + */ + protected void handleTitle(char[] title) + { + } + + /** + * Constructs the tag from the given element. In this implementation, + * this is defined, but never called. + * @return the tag + */ + protected TagElement makeTag(Element element) + { + return makeTag(element, false); + } + + /** + * Constructs the tag from the given element. + * @param the tag base {@link javax.swing.text.html.parser.Element} + * @param isSupposed true if the tag is not actually present in the + * html input, but the parser supposes that it should to occur in + * the current location. + * @return the tag + */ + protected TagElement makeTag(Element element, boolean isSupposed) + { + return new TagElement(element, isSupposed); + } + + /** + * This is called when the tag, representing the given element, + * occurs first time in the document. + * @param element + */ + protected void markFirstTime(Element element) + { + } + + /** + * Consume the token that was checked before and hence MUST be present. + * @param kind The kind of token to consume. + */ + protected Token mustBe(int kind) + { + if (getTokenAhead().kind == kind) + return getNextToken(); + else + { + String ei = ""; + if (kind < 1000) + ei = " ('" + (char) kind + "') "; + throw new AssertionError("The token of kind " + kind + ei + + " MUST be here," + ); + } + } + + /** + * Handle attribute without value. The default method uses + * the only allowed attribute value from DTD. + * If the attribute is unknown or allows several values, + * the HTML.NULL_ATTRIBUTE_VALUE is used. The attribute with + * this value is added to the attribute set. + * @param element The name of element. + * @param attribute The name of attribute without value. + */ + protected void noValueAttribute(String element, String attribute) + { + Object value = HTML.NULL_ATTRIBUTE_VALUE; + + Element e = dtd.elementHash.get(element.toLowerCase()); + if (e != null) + { + AttributeList attr = e.getAttribute(attribute); + if (attr != null) + { + Vector values = attr.values; + if (values != null && values.size() == 1) + value = values.get(0); + } + } + attributes.addAttribute(attribute, value); + } + + /** + * Consume the optional token, if present. + * @param kind The kind of token to consume. + */ + protected Token optional(int kind) + { + if (getTokenAhead().kind == kind) + return getNextToken(); + else + return null; + } + + /** Parse the html document. */ + protected void parseDocument() + throws ParseException + { + // Read up any initial whitespace. + optional(WS); + while (getTokenAhead().kind != EOF) + { + advanced = false; + if (TAG.matches(this)) + Tag(); + else if (COMMENT_OPEN.matches(this)) + Comment(); + else if (STYLE_OPEN.matches(this)) + Style(); + else if (SCRIPT_OPEN.matches(this)) + Script(); + else if (SGML.matches(this)) + Sgml(); + else + CDATA(true); + + // Surely HTML error, treat as a text. + if (!advanced) + { + Token wrong = getNextToken(); + error("unexpected '" + wrong.getImage() + "'", wrong); + buffer.setLength(0); + buffer.append(wrong.getImage()); + _handleText(); + } + } + } + + /** + * Read the element attributes, adding them into attribute set. + * @param element The element name (needed to access attribute + * information in dtd). + */ + protected void readAttributes(String element) + { + Token name; + Token value; + Token next; + String attrValue; + + attributes = new htmlAttributeSet(); + + optional(WS); + + attributeReading: + while (getTokenAhead().kind == NUMTOKEN) + { + name = getNextToken(); + optional(WS); + + next = getTokenAhead(); + if (next.kind == EQ) + { + mustBe(EQ); + optional(WS); + + next = getNextToken(); + + switch (next.kind) + { + case QUOT: + + // read "quoted" attribute. + buffer.setLength(0); + readTillTokenE(QUOT); + attrValue = buffer.toString(); + break; + + case AP: + + // read 'quoted' attribute. + buffer.setLength(0); + readTillTokenE(AP); + attrValue = buffer.toString(); + break; + + // read unquoted attribute. + case NUMTOKEN: + value = next; + optional(WS); + + // Check maybe the opening quote is missing. + next = getTokenAhead(); + if (bQUOTING.get(next.kind)) + { + hTag = next; + error("The value without opening quote is closed with '" + + next.getImage() + "'"); + attrValue = value.getImage(); + } + else if (next.kind == SLASH || next.kind == OTHER) + // The slash and other characters (like %) in this context is + // treated as the ordinary + // character, not as a token. The character may be part of + // the unquoted URL. + { + CPStringBuilder image = new CPStringBuilder(value.getImage()); + while (next.kind == NUMTOKEN || next.kind == SLASH + || next.kind == OTHER) + { + image.append(getNextToken().getImage()); + next = getTokenAhead(); + } + attrValue = image.toString(); + } + else + attrValue = value.getImage(); + break; + + case SLASH: + value = next; + optional(WS); + + // Check maybe the opening quote is missing. + next = getTokenAhead(); + if (bQUOTING.get(next.kind)) + { + hTag = next; + error("The value without opening quote is closed with '" + + next.getImage() + "'"); + attrValue = value.getImage(); + } + else if (next.kind == NUMTOKEN || next.kind == SLASH) + // The slash in this context is treated as the ordinary + // character, not as a token. The slash may be part of + // the unquoted URL. + { + CPStringBuilder image = new CPStringBuilder(value.getImage()); + while (next.kind == NUMTOKEN || next.kind == SLASH) + { + image.append(getNextToken().getImage()); + next = getTokenAhead(); + } + attrValue = image.toString(); + } + else + attrValue = value.getImage(); + break; + default: + break attributeReading; + } + attributes.addAttribute(name.getImage(), attrValue); + optional(WS); + } + else + // The '=' is missing: attribute without value. + { + noValueAttribute(element, name.getImage()); + } + } + } + + /** + * Return string, corresponding the given named entity. The name is passed + * with the preceeding &, but without the ending semicolon. + */ + protected String resolveNamedEntity(final String a_tag) + { + // Discard & + if (!a_tag.startsWith("&")) + throw new AssertionError("Named entity " + a_tag + + " must start witn '&'." + ); + + String tag = a_tag.substring(1); + + try + { + Entity entity = dtd.getEntity(tag); + if (entity != null) + return entity.getString(); + + entity = dtd.getEntity(tag.toLowerCase()); + + if (entity != null) + { + error("The name of this entity should be in lowercase", a_tag); + return entity.getString(); + } + } + catch (IndexOutOfBoundsException ibx) + { + /* The error will be reported. */ + } + + error("Unknown named entity", a_tag); + return a_tag; + } + + /** + * Return char, corresponding the given numeric entity. + * The name is passed with the preceeding &#, but without + * the ending semicolon. + */ + protected char resolveNumericEntity(final String a_tag) + { + // Discard &# + if (!a_tag.startsWith("&#")) + throw new AssertionError("Numeric entity " + a_tag + + " must start witn '&#'." + ); + + String tag = a_tag.substring(2); + + try + { + // Determine the encoding type: + char cx = tag.charAt(0); + if (cx == 'x' || cx == 'X') // Hexadecimal &#Xnnn; + + return (char) Integer.parseInt(tag.substring(1), 16); + + return (char) Integer.parseInt(tag); + } + + /* The error will be reported. */ + catch (NumberFormatException nex) + { + } + catch (IndexOutOfBoundsException ix) + { + } + + error("Invalid numeric entity", a_tag); + return '?'; + } + + /** + * Reset all fields into the intial default state, preparing the + * parset for parsing the next document. + */ + protected void restart() + { + documentTags.clear(); + titleHandled = false; + titleOpen = false; + buffer.setLength(0); + title.setLength(0); + validator.restart(); + } + + /** + * The method is called when the HTML opening tag ((like <table>) + * is found or if the parser concludes that the one should be present + * in the current position. The method is called immediately before + * calling the handleStartTag. + * @param tag The tag + */ + protected void startTag(TagElement tag) + throws ChangedCharSetException + { + } + + /** + * Handle a complete element, when the tag content is already present in the + * buffer and both starting and heading tags behind. This is called + * in the case when the tag text must not be parsed for the nested + * elements (elements STYLE and SCRIPT). + */ + private void _handleCompleteElement(TagElement tag) + { + _handleStartTag(tag); + + // Suppress inclusion of the SCRIPT ans STYLE texts into the title. + HTML.Tag h = tag.getHTMLTag(); + if (h == HTML.Tag.SCRIPT || h == HTML.Tag.STYLE) + { + boolean tmp = titleOpen; + titleOpen = false; + _handleText(); + titleOpen = tmp; + } + else + _handleText(); + + _handleEndTag(tag); + } + + /** + * A hooks for operations, preceeding call to handleEmptyTag(). + * Handle the tag with no content, like <br>. As no any + * nested tags are expected, the tag validator is not involved. + * @param tag The tag being handled. + */ + private void _handleEmptyTag(TagElement tag) + { + try + { + validator.validateTag(tag, attributes); + handleEmptyTag(tag); + HTML.Tag h = tag.getHTMLTag(); + // When a block tag is closed, consume whitespace that follows after + // it. + // For some unknown reason a FRAME tag is not treated as block element. + // However in this case it should be treated as such. + if (isBlock(h)) + optional(WS); + } + catch (ChangedCharSetException ex) + { + error("Changed charset exception:", ex.getMessage()); + } + } + + /** + * A hooks for operations, preceeding call to handleEndTag(). + * The method is called when the HTML closing tag + * is found. Calls handleTitle after closing the 'title' tag. + * @param tag The tag + */ + private void _handleEndTag(TagElement tag) + { + if (validator.closeTag(tag)) + _handleEndTag_remaining(tag); + } + + /** + * Actions that are also required if the closing action was + * initiated by the tag validator. + * Package-private to avoid an accessor method. + */ + void _handleEndTag_remaining(TagElement tag) + { + HTML.Tag h = tag.getHTMLTag(); + + handleEndTag(tag); + endTag(tag.fictional()); + + if (h.isPreformatted()) + preformatted--; + if (preformatted < 0) + preformatted = 0; + + // When a block tag is closed, consume whitespace that follows after + // it. + if (isBlock(h)) + optional(WS); + + if (h == HTML.Tag.TITLE) + { + titleOpen = false; + titleHandled = true; + + char[] a = new char[ title.length() ]; + title.getChars(0, a.length, a, 0); + handleTitle(a); + } + } + + /** + * A hooks for operations, preceeding call to handleStartTag(). + * The method is called when the HTML opening tag ((like <table>) + * is found. + * Package-private to avoid an accessor method. + * @param tag The tag + */ + void _handleStartTag(TagElement tag) + { + validator.openTag(tag, attributes); + startingTag(tag); + handleStartTag(tag); + + HTML.Tag h = tag.getHTMLTag(); + + if (isBlock(h)) + optional(WS); + + if (h.isPreformatted()) + preformatted++; + + if (h == HTML.Tag.TITLE) + { + if (titleHandled) + error("Repetetive tag"); + titleOpen = true; + titleHandled = false; + } + } + + /** + * Resume parsing after heavy errors in HTML tag structure. + * @throws ParseException + */ + private void forciblyCloseTheTag() + throws ParseException + { + int closeAt = 0; + buffer.setLength(0); + + ahead: + for (int i = 1; i < 100; i++) + { + t = getTokenAhead(i - 1); + if (t.kind == EOF || t.kind == BEGIN) + break ahead; + if (t.kind == END) + { + /* Closing '>' found. */ + closeAt = i; + break ahead; + } + } + if (closeAt > 0) + { + buffer.append("Ignoring '"); + for (int i = 1; i <= closeAt; i++) + { + t = getNextToken(); + append(t); + } + buffer.append('\''); + error(buffer.toString()); + } + } + + /** + * Handle comment in string buffer. You can avoid allocating a char + * array each time by processing your comment directly here. + */ + private void handleComment() + { + char[] a = new char[ buffer.length() ]; + buffer.getChars(0, a.length, a, 0); + handleComment(a); + } + + private TagElement makeTagElement(String name, boolean isSupposed) + { + Element e = dtd.elementHash.get(name.toLowerCase()); + if (e == null) + { + error("Unknown tag <" + name + ">"); + e = dtd.getElement(name); + e.name = name.toUpperCase(); + e.index = -1; + } + + if (!documentTags.contains(e.name)) + { + markFirstTime(e); + documentTags.add(e.name); + } + + return makeTag(e, isSupposed); + } + + /** + * Read till the given token, resolving entities. Consume the given + * token without adding it to buffer. + * @param till The token to read till + * @throws ParseException + */ + private void readTillTokenE(int till) + throws ParseException + { + buffer.setLength(0); + read: + while (true) + { + t = getNextToken(); + if (t.kind == Constants.ENTITY) + { + resolveAndAppendEntity(t); + } + else if (t.kind == EOF) + { + error("unexpected eof", t); + break read; + } + else if (t.kind == till) + break read; + else if (t.kind == WS) + { + // Processing whitespace in accordance with CDATA rules: + String s = t.getImage(); + char c; + for (int i = 0; i < s.length(); i++) + { + c = s.charAt(i); + if (c == '\r') + buffer.append(' '); // CR replaced by space + else if (c == '\n') + { /* LF ignored */ } + else if (c == '\t') + buffer.append(' '); // Tab replaced by space + else + buffer.append(c); + } + } + else + append(t); + } + } + + /** + * Resolve the entity and append it to the end of buffer. + * @param entity + */ + private void resolveAndAppendEntity(Token entity) + { + switch (entity.category) + { + case ENTITY_NAMED : + buffer.append(resolveNamedEntity(entity.getImage())); + break; + + case ENTITY_NUMERIC : + buffer.append(resolveNumericEntity(entity.getImage())); + break; + + default : + throw new AssertionError("Invalid entity category " + + entity.category + ); + } + } + + /** + * Handle the remaining of HTML tags. This is a common end for + * TAG, SCRIPT and STYLE. + * @param closing True for closing tags ( </TAG> ). + * @param name Name of element + * @param start Token where element has started + * @throws ParseException + */ + private void restOfTag(boolean closing, Token name, Token start) + throws ParseException + { + boolean end = false; + Token next; + + optional(WS); + + readAttributes(name.getImage()); + + optional(WS); + + next = getTokenAhead(); + if (next.kind == END) + { + mustBe(END); + end = true; + } + + hTag = new Token(start, next); + + if (!end) + { + // The tag body contains errors. If additionally the tag + // name is not valid, this construction is treated as text. + if (dtd.elementHash.get(name.getImage().toLowerCase()) == null && + backupMode + ) + { + error("Errors in tag body and unknown tag name. " + + "Treating the tag as a text." + ); + reset(); + + hTag = mustBe(BEGIN); + buffer.setLength(0); + buffer.append(hTag.getImage()); + CDATA(false); + return; + } + else + { + error("Forcibly closing invalid parameter list"); + forciblyCloseTheTag(); + } + } + + if (closing) + { + endTag(false); + _handleEndTag(makeTagElement(name.getImage(), false)); + } + else + { + TagElement te = makeTagElement(name.getImage(), false); + if (te.getElement().type == DTDConstants.EMPTY) + _handleEmptyTag(te); + else + { + // According to the specs we need to consume whitespace following + // immediately after a opening tag. + optional(WS); + _handleStartTag(te); + } + } + } + + /** + * This should fire additional actions in response to the + * ChangedCharSetException. The current implementation + * does nothing. + * @param tag + */ + private void startingTag(TagElement tag) + { + try + { + startTag(tag); + } + catch (ChangedCharSetException cax) + { + error("Invalid change of charset"); + } + } + + private void ws_error() + { + error("Whitespace here is not permitted"); + } + + /** + * Returns true when the specified tag should be considered a block tag + * wrt whitespace handling. We need this special handling, since there + * are a couple of tags that we must treat as block tags but which aren't + * officially block tags. + * + * @param tag the tag to check + * @return true when the specified tag should be considered a block tag + * wrt whitespace handling + */ + private boolean isBlock(HTML.Tag tag) + { + return tag.isBlock() || tag == HTML.Tag.STYLE || tag == HTML.Tag.FRAME; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/gnuStringIntMapper.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/gnuStringIntMapper.java new file mode 100644 index 000000000..9cdf810dd --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/gnuStringIntMapper.java @@ -0,0 +1,112 @@ +/* gnuStringIntMapper.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.parser.support; + +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; + +/** + * A helper class, mapping between the strings and they unique integer + * identifiers. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public abstract class gnuStringIntMapper +{ + /** + * Maps argument integer values from DTDConstants into they string + * names. Initialized on demand. + */ + private Map is_Map; + + /** + * Maps argument string names into they integer values from DTDConstants. + * Initialized on demand. + */ + private Map si_Map; + + /** + * Get string from id or null if no such id is present in the mapper. + */ + public final String get(int id) + { + if (is_Map == null) + createTheMap(); + + return (String) is_Map.get(new Integer(id)); + } + + /** Get id from string or 0 if no such string is present in the mapper. */ + public final int get(String id) + { + if (si_Map == null) + createTheMap(); + + Integer i = (Integer) si_Map.get(id); + + return i != null ? i.intValue() : 0; + } + + /** + * Create the mapping table for this mapper by adding the required + * String/int pairs. The method is invoked + * only once for each instance, after the first invocation of the any + * form of the <code>get</code> method. Use <code>add</code> to + * create a map for a concrete instance. + */ + protected abstract void create(); + + /** + * Add an id/string pair to this mapper. This is called from + * the method <code>create</code> only. + */ + protected void add(String name, int id) + { + Integer i = new Integer(id); + si_Map.put(name, i); + is_Map.put(i, name); + } + + private void createTheMap() + { + is_Map = new HashMap(); + si_Map = new TreeMap(); + create(); + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Buffer.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Buffer.java new file mode 100644 index 000000000..a39330af8 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Buffer.java @@ -0,0 +1,238 @@ +/* Buffer.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.parser.support.low; + +/** + * A string buffer that additionally holds line and absolute postion + * information. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class Buffer +{ + public static int INITIAL_SIZE = 2048; + + /** + * True if the \n symbol has been seen. + */ + public boolean n_seen; + + /** + * True if the \r symbol has been seen. + */ + public boolean r_seen; + char[] chr = new char[ INITIAL_SIZE ]; + int[] line = new int[ INITIAL_SIZE ]; + int[] position = new int[ INITIAL_SIZE ]; + + /** + * Current line. + */ + int current_line = 0; + + /** + * Point to the next free position. + */ + int length; + + public Buffer() + { + } + + public Buffer(String content) + { + for (int i = 0; i < content.length(); i++) + { + append(content.charAt(i), i); + } + } + + /** + * Get the characters into array. + * @param srcBegin From, inclusive + * @param srcEnd To, exclusive. + * @param dst Into + * @param dstBegin Offset. + */ + public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) + { + System.arraycopy(chr, srcBegin, dst, dstBegin, (srcEnd - srcBegin)); + } + + /** + * Return the sequence, used to separate lines in the document. + * @return one of \n, \r or \r\n. + */ + public String getEndOfLineSequence() + { + if (r_seen && n_seen) + return "\r\n"; + else if (r_seen) + return "\r"; + else + + // This also is returned for single-line document. + return "\n"; + } + + /** + * Truncate. + * @param n The length to truncate till. + */ + public void setLength(int n) + { + length = n; + } + + /** + * Get location information for the given region. + * @param from Region start, inclusive. + * @param to Region end, exclusive. + * @return The location, covering the region. + */ + public Location getLocation(int from, int to) + { + Location l = new Location(); + l.beginLine = line [ from ]; + l.endLine = line [ to - 1 ]; + + l.startPosition = position [ from ]; + l.endPosition = position [ to - 1 ] + 1; + + return l; + } + + /** + * Add the character. + * @param c The character. + * @param pos The character position in the stream (the line number + * is handled internally in the buffer). + */ + public void append(char c, int pos) + { + if (length >= chr.length) + expand(); + chr [ length ] = c; + position [ length ] = pos; + + if (c == '\n') + { + if (!r_seen) + current_line++; + n_seen = true; + } + else if (c == '\r') + { + current_line++; + r_seen = true; + } + + line [ length ] = current_line; + + length++; + } + + /** + * Return char at the given positon. + */ + public char charAt(int i) + { + return chr [ i ]; + } + + /** + * Delete the range + * @param from Start position, inclusive. + * @param to End position, exclusive. + */ + public void delete(int from, int to) + { + int len = to - from; + if (len < 1) + throw new AssertionError("Deleting " + from + " till " + to); + + int tail = length - to; + + System.arraycopy(chr, to, chr, from, tail); + System.arraycopy(position, to, position, from, tail); + System.arraycopy(line, to, line, from, tail); + length = length - len; + } + + /** + * Double the buffer size. + */ + public void expand() + { + int nSize = 2 * chr.length; + + char[] nchr = new char[ nSize ]; + int[] nposition = new int[ nSize ]; + int[] nline = new int[ nSize ]; + + System.arraycopy(chr, 0, nchr, 0, chr.length); + System.arraycopy(position, 0, nposition, 0, position.length); + System.arraycopy(line, 0, nline, 0, line.length); + + chr = nchr; + position = nposition; + line = nline; + } + + /** + * Return length of the occupied part of the buffer. + */ + public int length() + { + return length; + } + + /** + * Prepare for parsing the new document. + */ + public void reset() + { + setLength(0); + r_seen = n_seen = false; + } + + public String toString() + { + return new String(chr, 0, length); + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Constants.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Constants.java new file mode 100644 index 000000000..5416582ad --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Constants.java @@ -0,0 +1,433 @@ +/* Constants.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.parser.support.low; + +import java.util.BitSet; + +/** + * The parser constants and operations, directly related to the parser + * constants. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class Constants +{ + /* Single character tokens are reflected into they ASCII codes. */ + + /** + * Start of HTML token. + */ + public static final int BEGIN = '<'; + + /** + * End of HTML token. + */ + public static final int END = '>'; + + /** + * Exclamation (indicates SGML or comment). + */ + public static final int EXCLAMATION = '!'; + + /** + * Slash (indicates closing tag). + */ + public static final int SLASH = '/'; + + /** + * Equals sign. + */ + public static final int EQ = '='; + + /** + * Quoting sign. + */ + public static final int AP = '\''; + + /** + * Quoting sign. + */ + public static final int QUOT = '"'; + + /* The numbers of other tokens start outside the ascii space. */ + /* String tokens */ + + /** + * Double dash (--) + */ + public static final int DOUBLE_DASH = 1000; + + /** + * The STYLE tag (needs special handling). + */ + public static final int STYLE = 1001; + + /** + * The SCRIPT tag (needs special handling). + */ + public static final int SCRIPT = 1002; + + /* Pattern tokens */ + + /** + * HTML whitespace. + */ + public static final int WS = 1003; + + /** + * Named or numeric entity, + */ + public static final int ENTITY = 1004; + + /** + * Sequence of valid name characters (can start from digit). + */ + public static final int NUMTOKEN = 1005; + + /* Complex tokens */ + + /** + * Comment opening sequence. + */ + public static final pattern COMMENT_OPEN = + new pattern(new node[] + { + new node(BEGIN), new node(WS, true), new node(EXCLAMATION), + new node(WS, true), new node(DOUBLE_DASH), + } + ); + + /** + * Comment closing sequence + */ + public static final pattern COMMENT_END = + new pattern(new node[] + { + new node(DOUBLE_DASH), new node(WS, true), new node(END) + } + ); + + /** + * Special case ---> (also is treated as end of comment). + */ + public static final pattern COMMENT_TRIPLEDASH_END = + new pattern(new node[] + { + new node(DOUBLE_DASH), new node(NUMTOKEN), new node(END) + } + ); + + /** + * STYLE element heading pattern. + */ + public static final pattern STYLE_OPEN = + new pattern(new node[] { new node(BEGIN), new node(WS, true), new node(STYLE) }); + + /** + * SCRIPT element heading pattern. + */ + public static final pattern SCRIPT_OPEN = + new pattern(new node[] { new node(BEGIN), new node(WS, true), new node(SCRIPT) }); + + /** + * SGML element heading pattern. + */ + public static final pattern SGML = + new pattern(new node[] + { + new node(BEGIN), new node(WS, true), new node(EXCLAMATION) + } + ); + + /** + * SCRIPT element closing pattern. + */ + public static final pattern SCRIPT_CLOSE = + new pattern(new node[] + { + new node(BEGIN), new node(WS, true), new node(SLASH), + new node(WS, true), new node(SCRIPT), new node(WS, true), + new node(END) + } + ); + + /** + * STYLE element closing pattern. + */ + public static final pattern STYLE_CLOSE = + new pattern(new node[] + { + new node(BEGIN), new node(WS, true), new node(SLASH), + new node(WS, true), new node(STYLE), new node(WS, true), + new node(END) + } + ); + + /** + * Ordinary HTML tag heading pattern. + */ + public static final pattern TAG = + new pattern(new node[] + { + new node(BEGIN), new node(WS, true), new node(SLASH, true), + new node(WS, true), new node(NUMTOKEN) + } + ); + + /** + * Ordinary HTML tag closing pattern. + */ + public static final pattern TAG_CLOSE = + new pattern(new node[] + { + new node(BEGIN), new node(WS, true), new node(SLASH), + new node(WS, true), new node(NUMTOKEN) + } + ); + + /* Special tokens */ + + /** + * All other tokens. + */ + public static final int OTHER = 1999; + + /** + * The UNICODE "end of text" control code + */ + static final char ETX = 3; + + /** + * End of file. + */ + public static final int EOF = ETX; + + /* Character categories */ + + /** + * All single char tokens. + */ + public static final BitSet bSINGLE_CHAR_TOKEN = new BitSet(); + + /** + * Non letters and non numbers, allowed in HTML names. + */ + public static final BitSet bSPECIAL = new BitSet(); + + /** + * All letters, used in HTML names. + */ + public static final BitSet bLETTER = new BitSet(); + + /** + * Digits. + */ + public static final BitSet bDIGIT = new BitSet(); + + /** + * Both line breaks. + */ + public static final BitSet bLINEBREAK = new BitSet(); + + /** + * All whitespace. + */ + public static final BitSet bWHITESPACE = new BitSet(); + + /** + * Both quoting characters. + */ + public static final BitSet bQUOTING = new BitSet(); + + /** + * Valid name characters. + */ + public static final BitSet bNAME = new BitSet(); + + /* Entity subcategories */ + + /** + * Named entity. + */ + public static final int ENTITY_NAMED = 1; + + /** + * Numeric entity. + */ + public static final int ENTITY_NUMERIC = 2; + + static + { + bQUOTING.set(AP); + bQUOTING.set(QUOT); + + bSINGLE_CHAR_TOKEN.set(BEGIN); + bSINGLE_CHAR_TOKEN.set(END); + bSINGLE_CHAR_TOKEN.set(EXCLAMATION); + bSINGLE_CHAR_TOKEN.set(SLASH); + bSINGLE_CHAR_TOKEN.set(EQ); + bSINGLE_CHAR_TOKEN.set(EOF); + + bSINGLE_CHAR_TOKEN.or(bQUOTING); + + bLINEBREAK.set('\r'); + bLINEBREAK.set('\n'); + + bWHITESPACE.set(' '); + bWHITESPACE.set('\t'); + bWHITESPACE.set(0xC); + bWHITESPACE.or(bLINEBREAK); + + for (char i = '0'; i <= '9'; i++) + { + bDIGIT.set(i); + } + + for (char i = 'a'; i <= 'z'; i++) + { + bLETTER.set(i); + } + + for (char i = 'A'; i <= 'Z'; i++) + { + bLETTER.set(i); + } + + bSPECIAL.set('-'); + bSPECIAL.set('_'); + bSPECIAL.set(':'); + bSPECIAL.set('.'); + + bNAME.or(bLETTER); + bNAME.or(bDIGIT); + bNAME.or(bSPECIAL); + } + + /** + * Verifies if one of the tokens matches the end of string + * buffer. The last character in the string buffer is the + * "future character", some tokens needs to verify it the + * token does not continue "towards the future". If the token + * matches, it matches till "pre-last" character in the buffer. + * @param b + * @return + */ + public Token endMatches(Buffer b) + { + if (b.length() < 2) + return null; + + int p = b.length() - 2; + + if (b.length() > 2 && b.charAt(p) == '-' && b.charAt(p - 1) == '-') + return new Token(DOUBLE_DASH, "--", b.getLocation(p - 1, p + 1)); + + char last = b.charAt(p); + + if (bSINGLE_CHAR_TOKEN.get(last)) + return new Token(last, last, b.getLocation(p, p + 1)); + + char future = b.charAt(p + 1); + + // Check for numtokens, script and style: + if (bNAME.get(last) && !bNAME.get(future)) + { + // Scan the history up: + int u = p - 1; + while (u >= 0 && bNAME.get(b.charAt(u))) + u--; + u++; + + char[] token = new char[ p - u + 1 ]; + + // Found a numtoken + b.getChars(u, p + 1, token, 0); + + // Verify for the built-in tokens: + String e = new String(token); + + // found the entity reference + if (u > 0 && b.charAt(u - 1) == '&') + { + // The subsequent semicolon may be the part of the token + // as well. The semicolon must be ignored. This must be + // handled elsewhere. + return new Token(ENTITY, ENTITY_NAMED, "&" + e, + b.getLocation(u - 1, p + 1) + ); + } + + // found the numeric entity reference + if (u > 1 && b.charAt(u - 1) == '#' && b.charAt(u - 2) == '&') + { + // The subsequent semicolon may be the part of the token + // as well. The semicolon must be ignored. This must be + // handled elsewhere. + return new Token(ENTITY, ENTITY_NUMERIC, "&#" + e, + b.getLocation(u - 2, p + 2) + ); + } + + Location le = b.getLocation(u, p + 1); + + if (e.equalsIgnoreCase("SCRIPT")) + return new Token(SCRIPT, e, le); + else if (e.equalsIgnoreCase("STYLE")) + return new Token(STYLE, e, le); + else + return new Token(NUMTOKEN, e, le); + } + + // Check for whitespace + if (bWHITESPACE.get(last) && !bWHITESPACE.get(future)) + { + // Scan the history up: + int u = p - 1; + while (u >= 0 && bWHITESPACE.get(b.charAt(u))) + u--; + u++; + + char[] token = new char[ p - u + 1 ]; + b.getChars(u, p + 1, token, 0); + + return new Token(WS, new String(token), b.getLocation(u, p + 1)); + } + + return null; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Location.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Location.java new file mode 100644 index 000000000..8a1cde1c8 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Location.java @@ -0,0 +1,83 @@ +/* Location.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.parser.support.low; + +/** + * Defines a region in the text: its bounding positions and the line number. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class Location +{ + /** + * The line number, where the token starts. + */ + public int beginLine; + + /** + * The line, where the token ends. + */ + public int endLine; + + /** + * The absolute token end position in the input stream, + * exclusive. + */ + public int endPosition; + + /** + * The absolute token start position in the input stream, + * inclusive. + */ + public int startPosition; + + public Location() + { + } + + /** + * Special case, used to mark EOF. + * @param p The total stream length. + */ + public Location(int p) + { + startPosition = p; + endPosition = p + 1; + beginLine = endLine = -1; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/ParseException.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/ParseException.java new file mode 100644 index 000000000..e71c0c1f6 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/ParseException.java @@ -0,0 +1,51 @@ +/* ParseException.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.parser.support.low; + +/** + * This can be thrown from various parsing methods. + */ +public class ParseException + extends RuntimeException +{ + public ParseException(String s, Throwable cause) + { + super(s, cause); + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Queue.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Queue.java new file mode 100644 index 000000000..31cf4bb4d --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Queue.java @@ -0,0 +1,142 @@ +/* Queue.java -- a token queue. + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.parser.support.low; + +import java.util.Arrays; + +/** + * A token queue. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class Queue +{ + Token[] m = new Token[ 64 ]; + int a = 0; + int b = 0; + + /** + * True for the empty queue. + */ + public boolean isEmpty() + { + return size() == 0; + } + + /** + * Add this trace to the end of the queue. + */ + public void add(Token u) + { + if (a < m.length) + { + m [ a ] = u; + a++; + } + else // The end of array has been reached. + { + if (b > 0) // If some elements were deleted from the start of the queue, shift. + { + int d = b; + System.arraycopy(m, b, m, 0, a - b); + b = b - d; + a = a - d; + m [ a ] = u; + a++; + } + else // Enlarge the queue, doubling the size. + { + int n = m.length * 2; + Token[] nm = new Token[ 2 * n ]; + System.arraycopy(m, 0, nm, 0, m.length); + Arrays.fill(m, null); + + nm [ a ] = u; + m = nm; + a++; + } + } + } + + /** + * Clear the queue. + */ + public void clear() + { + a = b = 0; + Arrays.fill(m, null); + } + + /** + * Read the value ahead. 0 is the value that will be returned with + * the following next. This method does not remove values from the + * queue. To test if there is enough tokens in the queue, size() must + * be checked before calling this method. + */ + public Token get(int ahead) + { + int p = b + ahead; + if (p < a) + return m [ p ]; + else + throw new ArrayIndexOutOfBoundsException("Not enough tokens"); + } + + /** + * Read the oldest value from the queue and remove this value from + * the queue. + */ + public Token next() + { + if (a == b) + throw new ArrayIndexOutOfBoundsException("queue empty"); + + Token r = m [ b ]; + m [ b ] = null; + b++; + return r; + } + + /** + * Size of the queue. + */ + public int size() + { + return a - b; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/ReaderTokenizer.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/ReaderTokenizer.java new file mode 100644 index 000000000..45ac181b3 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/ReaderTokenizer.java @@ -0,0 +1,373 @@ +/* ReaderTokenizer.java -- splits the input char sequence int tokens. + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.parser.support.low; + +import java.io.IOException; +import java.io.Reader; + +/** + * Reader splits the input char sequence into tokens. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class ReaderTokenizer + extends Constants +{ + /** + * This is set to true each time the getNextToken is called. + * Used in preventing loops when all patterns refuse to accept + * the invalid input. + */ + protected boolean advanced; + + /** + * If true, the returned tokens are also placed in the backup + * queue. + */ + protected boolean backupMode; + + /** + * The buffer to read document into. + */ + Buffer buffer = new Buffer(); + + /** + * The queue for supporting mark(). + */ + Queue backup = new Queue(); + + /** + * The queue of found tokens. + */ + Queue queue = new Queue(); + + /** + * The reader to read the document from. + */ + Reader reader; + + /** + * Array of char tokens + */ + char[] charTokens; + + /** + * Array of string tokens. + */ + String[] stringTokens; + + /** + * The current reader position. + */ + int readerPosition = -1; + + /** + * Creates a new ReaderTokenizer. The reset(...) method must be + * subsequently called to set the reader. + */ + public ReaderTokenizer() + { + } + + /** + * Return the sequence, used to separate lines in the document. + * @return one of \n, \r or \r\n. + */ + public String getEndOfLineSequence() + { + return buffer.getEndOfLineSequence(); + } + + /** + * Get the next token. + * @return + */ + public Token getNextToken() + { + Token rt; + advanced = true; + try + { + if (queue.isEmpty()) + read(1); + + if (!queue.isEmpty()) + rt = queue.next(); + else + rt = new Token(EOF, new Location(readerPosition)); + } + catch (IOException ex) + { + throw new ParseException("IO Exception", ex); + } + if (backupMode) + backup.add(rt); + return rt; + } + + /** + * Get a token, lying the given number of tokens + * ahead. getToken(0) will return the same token, + * what would be returned by getNextToken(). + * getToken(..) does change the current position + * in the input stream. If the end of stream is + * reached, the EOF token is always returned. + */ + public Token getTokenAhead(int ahead) + { + try + { + read(ahead - queue.size() + 1); + return queue.size() >= ahead ? queue.get(ahead) : eofToken(); + } + catch (IOException ex) + { + throw new ParseException("IO Exception", ex); + } + } + + /** + * Get a token, bein immediatley ahead. + * If the end of stream is + * reached, the EOF token is always returned. + * The method is equivalent calling getTokenAhead(0). + */ + public Token getTokenAhead() + { + try + { + if (queue.isEmpty()) + read(1); + if (!queue.isEmpty()) + return queue.get(0); + else + return eofToken(); + } + catch (IOException ex) + { + throw new ParseException("IO Exception", ex); + } + } + + /** + * Invokes the error handler. + */ + public void error(String msg, Token at) + { + System.out.println(msg); + } + + /** + * Turns the backup mode on or off. + * It is possible to return where the mark(true) was last called + * by calling reset(). + * @param mode True if it is required to save tokens, making + * returning to the current point possible. + */ + public void mark(boolean mode) + { + backup.clear(); + backupMode = mode; + } + + /** + * Prepare for new parsing from the given stream. + * @param a_reader A reader to parse from. + */ + public void reset(Reader a_reader) + { + reader = a_reader; + readerPosition = -1; + buffer.reset(); + queue.clear(); + } + + /** + * Reset the internal cursor to the position where the mark() + * was last time called. Switches the backup mode off. + */ + public void reset() + { + if (!backupMode) + throw new AssertionError("Call mark(true) before using reset()!"); + backupMode = false; + + // That is now in the queue, will be appended to the end of backup. + while (!queue.isEmpty()) + backup.add(queue.next()); + + Queue t = queue; + queue = backup; + backup = t; + backup.clear(); + } + + /** + * Read the given number of the tokens. Add the needed number of EOF + * tokens if there are no more data in the stream. + * @param numberOfTokens The number of additional tokens to read. + */ + void read(int numberOfTokens) + throws IOException + { + if (numberOfTokens <= 0) + return; + + for (int i = 0; i < numberOfTokens; i++) + readToken(); + } + + /** + * Read next token from the reader, add it to the queue + */ + void readToken() + throws IOException + { + Token t; + int ch; + + enlarging: + while (true) + { + t = tokenMatches(); + if (t != null) + break enlarging; + else + { + ch = reader.read(); + readerPosition++; + if (ch == ETX) + ch = ' '; + if (ch < 0) + { + if (buffer.length() == 0) + { + queue.add(eofToken()); + return; + } + else + { + if (buffer.charAt(buffer.length() - 1) != ETX) + buffer.append(ETX, readerPosition++); + else + { + // Discard terminating ETX + buffer.setLength(buffer.length() - 1); + if (buffer.length() > 0) + { + t = new Token(OTHER, buffer.toString(), + buffer.getLocation(0, buffer.length()) + ); + queue.add(t); + buffer.setLength(0); + } + return; + } + } + } + else + buffer.append((char) ch, readerPosition); + } + } + } + + /** + * Check if the end of buffer matches one of the tokens. If it does, + * return this token and remove the token sequence from the end of + * buffer. + * @return The matching token. + */ + Token tokenMatches() + { + Token rt = endMatches(buffer); + if (rt != null) // Remove the matched image + { + // Consume future character if it was an entity and the future + // character is semicolon. + if (rt.kind == ENTITY) + { + if (buffer.charAt(buffer.length() - 1) == ';') + buffer.setLength(buffer.length() - rt.getImage().length() - 1); + else + { + error("Missing closing semicolon for entity '" + rt.getImage() + + "'", rt + ); + consumeBuffer(rt); + } + } + else + { + consumeBuffer(rt); + } + } + + // If the buffer is not empty, some sequence does not match any tokens. + // Add it to the queue as "OTHER". + if (rt != null) + { + if (buffer.length() > 1) + { + String rest = buffer.toString(); + rest = rest.substring(0, rest.length() - 1); + + Token other = + new Token(OTHER, rest, buffer.getLocation(0, buffer.length)); + queue.add(other); + consumeBuffer(other); + } + queue.add(rt); + } + return rt; + } + + private void consumeBuffer(Token rt) + { + buffer.delete(buffer.length() - rt.getImage().length() - 1, + buffer.length() - 1 + ); + } + + /** + * Create EOF token. + */ + private Token eofToken() + { + return new Token(EOF, "#", new Location(readerPosition)); + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Token.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Token.java new file mode 100644 index 000000000..d91adf47a --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Token.java @@ -0,0 +1,169 @@ +/* Token.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.parser.support.low; + +/** + * A token. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class Token +{ + /** + * The place of this token in the document. + */ + public Location where; + + /** + * The additional category of token. + */ + public int category; + + /** + * An integer that describes the kind of this token. + */ + public int kind; + + /** + * The string image of the token, null if the char image must be used. + */ + private String stringImage; + + /** + * The char image of the token. + */ + private char charImage; + + /** + * Creates a new token with fields, initialized to the default values. + */ + public Token() + { + } + + /** + * Creates a new token of the given kind. + */ + public Token(int _kind, Location _where) + { + kind = _kind; + where = _where; + } + + /** + * Creates a new token of the given kind and given single char image. + */ + public Token(int _kind, char _image, Location _where) + { + kind = _kind; + charImage = _image; + where = _where; + } + + /** + * Creates a new token of the given kind and given string image. + */ + public Token(int _kind, String _image, Location _where) + { + kind = _kind; + stringImage = _image; + where = _where; + } + + /** + * Creates a new token of the given kind, category and given string image. + */ + public Token(int _kind, int _category, String _image, Location _where) + { + kind = _kind; + category = _category; + stringImage = _image; + where = _where; + } + + /** + * Creates a new token, where location fields are set as for token, + * spanning over two provided tokens and any tokens between them. + * The image field is initialized to null, the kind field is set to -1. + */ + public Token(Token fromInclusive, Token toInclusive) + { + where = new Location(); + where.beginLine = fromInclusive.where.beginLine; + where.startPosition = fromInclusive.where.startPosition; + + where.endLine = toInclusive.where.endLine; + where.endPosition = toInclusive.where.endPosition; + } + + public String getImage() + { + if (kind == 3) + return "#"; + if (stringImage == null) + { + if (charImage == 0) + return null; + stringImage = new String(new char[] { charImage }); + } + return stringImage; + } + + /** + * Append the token image to the given string buffer. + * This may be more effective that buffer.append(this.getImage()). + * @param buffer A buffer to append. + */ + public void appendTo(StringBuffer buffer) + { + if (charImage == 0) + buffer.append(getImage()); + else + buffer.append(charImage); + } + + /** + * Returns the string image or, if null, the bounding positions. + */ + public String toString() + { + return getImage() != null ? kind + "'" + getImage() + : "<line " + where.beginLine + ", abs pos " + where.startPosition + + ".." + where.endPosition + ">"; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/node.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/node.java new file mode 100644 index 000000000..b54ed86a3 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/node.java @@ -0,0 +1,78 @@ +/* node.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.parser.support.low; + +/** + * A text level content model node. The only required unary operations + * here are "appears" and "optionally appears" ('?'). + * <p>@author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)</p> + */ +public class node +{ + /** + * True for node that is optional for the given position. + */ + public boolean optional; + + /** + * The kind of the token to match. + */ + public int kind; + + /** + * Creates the new node for matching a given kind of the token. + * @param kind The kind of the token to match. + * @param modifier The modifier (*?+). + */ + public node(int kind, boolean _optional) + { + this.kind = kind; + optional = _optional; + } + + /** + * Creates the node, indicating that token must match exactluy one time. + * @param kind The kind of token to match. + */ + public node(int kind) + { + this.kind = kind; + optional = false; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/package.html b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/package.html new file mode 100644 index 000000000..173583015 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/package.html @@ -0,0 +1,47 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in javax.swing.text.html.parser package. + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - gnu.javax.swing.text.html.parser.support.low + + +

    This package contains classes that are directly used to process +the text input: adapted stream tokenizer, specialized buffer and text-level content models .

    +@author Audrius Meskauskas, Lithuania + + diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/pattern.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/pattern.java new file mode 100644 index 000000000..0fe03fdbe --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/pattern.java @@ -0,0 +1,105 @@ +/* pattern.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.parser.support.low; + + +/** + * The simple pattern, consisting from the sequence of tokens that + * may have the unary modifier '?'. Choices and grouping + * are not required here. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class pattern +{ + /** + * The nodes of this pattern. + */ + public final node[] nodes; + + /** + * Create a pattern, containing the given list of nodes. + * @param a_nodes + */ + public pattern(node[] a_nodes) + { + nodes = a_nodes; + } + + /** + * Checks if the pattern can match the tokens in this + * tokenizer. Does not change the state of tokenizer. + * @param stream The tokenizer to read data from + * @return True if the pattern sequence matches the + * beginning of the tokenizer content. + */ + public boolean matches(ReaderTokenizer stream) + { + try + { + int pt = 0; + int pn = 0; + Token t; + node n; + + while (pn < nodes.length) + { + n = nodes [ pn ]; + t = stream.getTokenAhead(pt); + + if (t.kind == n.kind) + { + pn++; + pt++; + } + else + { + if (!n.optional) + return false; + else + pn++; + } + } + return true; + } + catch (Exception ex) + { + throw new ParseException("Exception", ex); + } + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/package.html b/libjava/classpath/gnu/javax/swing/text/html/parser/support/package.html new file mode 100644 index 000000000..97c6439b3 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/package.html @@ -0,0 +1,47 @@ + + + + +GNU Classpath - gnu.javax.swing.text.html.parser.support + + +

    This package provides various specialised classes, needed by HTML parser. +

    +@author Audrius Meskauskas, Lithuania + + diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/parameterDefaulter.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/parameterDefaulter.java new file mode 100644 index 000000000..43c07572a --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/parameterDefaulter.java @@ -0,0 +1,106 @@ +/* parameterDefaulter.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.parser.support; + +import gnu.javax.swing.text.html.parser.htmlAttributeSet; + +import java.util.Hashtable; + +import javax.swing.text.html.parser.AttributeList; +import javax.swing.text.html.parser.DTD; +import javax.swing.text.html.parser.Element; + +/** + * Returns an attribute set, containing default + * parameters for the given element. Caches sets of default + * parameters. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class parameterDefaulter +{ + public final DTD dtd; + Hashtable sets = new Hashtable(); + + /** + * Create a parameterDefaulter that looks for the default attribute + * values in the given DTD. + * @param a_dtd + */ + public parameterDefaulter(DTD a_dtd) + { + dtd = a_dtd; + } + + /** + * Get the default parameter set for the given element. + * @param element The element name (case insensitive). + * @return the default attrbute set. + */ + public htmlAttributeSet getDefaultParameters(String element) + { + String key = element.toLowerCase(); + htmlAttributeSet atts = (htmlAttributeSet) sets.get(key); + + if (atts == null) + { + htmlAttributeSet set = new htmlAttributeSet(); + Element e = dtd.elementHash.get(element.toLowerCase()); + + if (e != null) + { + AttributeList a = e.getAttributes(); + + while (a != null) + { + if (a.value != null) + set.addAttribute(a.name, a.value); + a = a.next; + } + } + + if (set.getAttributeCount() > 0) + sets.put(key, set); + else + sets.put(key, htmlAttributeSet.EMPTY_HTML_ATTRIBUTE_SET); + + atts = set; + } + return atts; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/textPreProcessor.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/textPreProcessor.java new file mode 100644 index 000000000..22c44be4f --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/textPreProcessor.java @@ -0,0 +1,189 @@ +/* textPreProcessor.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.text.html.parser.support; + +import gnu.javax.swing.text.html.parser.support.low.Constants; + +/** + * Pre - processes text in text parts of the html document. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class textPreProcessor +{ + /** + * Pre - process non-preformatted text. \t, \r and \n mutate into spaces, then + * multiple spaces mutate into single one, all whitespace around tags is + * consumed. The content of the passed buffer is destroyed. + * + * @param a_text A text to pre-process. + */ + public char[] preprocess(StringBuffer a_text) + { + if (a_text.length() == 0) + return null; + + char[] text = toCharArray(a_text); + + int a = 0; + int b = text.length - 1; + + // Remove leading/trailing whitespace, leaving at most one character + int len = text.length; + while (a + 1 < len && Constants.bWHITESPACE.get(text[a]) + && Constants.bWHITESPACE.get(text[a + 1])) + a++; + + while (b > a && Constants.bWHITESPACE.get(text[b]) + && Constants.bWHITESPACE.get(text[b - 1])) + b--; + + a_text.setLength(0); + + boolean spacesWere = false; + boolean spaceNow; + char c; + + chars: for (int i = a; i <= b; i++) + { + c = text[i]; + spaceNow = Constants.bWHITESPACE.get(c); + if (spacesWere && spaceNow) + continue chars; + if (spaceNow) + a_text.append(' '); + else + a_text.append(c); + spacesWere = spaceNow; + } + + if (a_text.length() == text.length) + { + a_text.getChars(0, a_text.length(), text, 0); + return text; + } + else + return toCharArray(a_text); + } + + /** + * Pre - process pre-formatted text. + * Heading/closing spaces and tabs preserved. + * ONE bounding \r, \n or \r\n is removed. + * \r or \r\n mutate into \n. Tabs are + * preserved. + * The content of the passed buffer is destroyed. + * @param a_text + * @return + */ + public char[] preprocessPreformatted(StringBuffer a_text) + { + if (a_text.length() == 0) + return null; + + char[] text = toCharArray(a_text); + + int a = 0; + int n = text.length - 1; + int b = n; + + if (text [ 0 ] == '\n') + a++; + else + { + if (text [ 0 ] == '\r') + { + a++; + if (text.length > 1 && text [ 1 ] == '\n') + a++; + } + } + + if (text [ n ] == '\r') + b--; + else + { + if (text [ n ] == '\n') + { + b--; + if (n > 0 && text [ n - 1 ] == '\r') + b--; + } + } + + a_text.setLength(0); + + if (a > b) + return null; + + char c; + + for (int i = a; i <= b; i++) + { + c = text [ i ]; + if (c == '\r') + { + if (i == b || text [ i + 1 ] != '\n') + a_text.append('\n'); + } + else + a_text.append(c); + } + + if (a_text.length() == text.length) + { + a_text.getChars(0, a_text.length(), text, 0); + return text; + } + else + return toCharArray(a_text); + } + + /** + * Return array of chars, present in the given buffer. + * @param a_text The buffer + * @return + */ + private static char[] toCharArray(StringBuffer a_text) + { + char[] text = new char[ a_text.length() ]; + a_text.getChars(0, text.length, text, 0); + return text; + } +} diff --git a/libjava/classpath/gnu/javax/swing/tree/GnuPath.java b/libjava/classpath/gnu/javax/swing/tree/GnuPath.java new file mode 100644 index 000000000..568ffd102 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/tree/GnuPath.java @@ -0,0 +1,65 @@ +/* GnuPath.java -- The extended version of TreePath + 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.swing.tree; + +import javax.swing.tree.TreePath; + +/** + * The tree path with additional data. Needed for the optimized tree drawing. + * Returned by layout caches. + * + * @author Audrius Meskauskas + */ +public class GnuPath extends TreePath +{ + /** + * The flag, marking the last visible child. + */ + public boolean isLastChild; + + /** + * Create a new path, specifying flag if this path is the path to the + * last visible child (needed for optimized tree drawing). + */ + public GnuPath(Object[] path, boolean lastChild) + { + super(path); + isLastChild = lastChild; + } +} -- cgit v1.2.3